import type { FC } from 'react';
import { useState } from 'react';
import React from 'react';
import {
    Button,
    type CountryOption,
    GlyphButton,
    Label,
    MarketSelector,
    Select,
    Tag,
    ToastContainer,
    SegmentedButton,
    InfoMessage,
    Section,
    Tooltip,
    MultiSelect,
} from '@theorchard/suite-components';
import { useIdentity } from '@theorchard/suite-frontend';
import {
    EMPTY_CHAR,
    META_VALUE,
    ROUTE_CATALOG_TRACK,
    TIKTOK_VALUE,
    YOUTUBE_VALUE,
} from 'src/constants';
import {
    useSetAudioAttributesMutation,
    useSetFingerprintRulesForTrackMutation,
    useSetRightsAttributesMutation,
} from 'src/data/mutations';
import DeliverySummary from 'src/pages/trackPage/views/rulesView/components/deliverySummary';
import UpdatedAddRule from 'src/pages/trackPage/views/rulesView/components/updatedAddRule';
import { PolicyType } from 'src/types';
import {
    useDisplayYoutubeFingerprintRulesFF,
    useShowCustomPoliciesFF,
} from 'src/utils/features';
import { canManageRules } from 'src/utils/permissions';
import { useRouteParams } from 'src/utils/route';
import AddAttribute from './components/addAttribute';
import DeliveryRulesTable from './components/deliveryRulesTable';
import type { PolicyFilter, ServiceFilter } from '../../trackPage';
import type { QueryParamsConfig } from '@theorchard/suite-frontend';
import type { AudioAttributes } from 'src/data/queries/audioAttributes/types';
import type { RightsAttributes } from 'src/data/queries/rightsAttributes/types';
import type { Territories } from 'src/data/queries/territories/types';
import type { FormattedTrack } from 'src/data/queries/track/selector';
import type { FingerprintRule, FingerprintRuleInput, Profile } from 'src/types';

const ALL_COUNTRIES_LENGTH = 249;
const GLOBAL_TITLE = 'Global';
const GLOBAL_CODE = 'GLOBAL';
export const PARENT_CLASS_NAME = 'TrackPage';
export const CLASS_NAME = `${PARENT_CLASS_NAME}-Views-RulesView`;

export const PAGE_QUERY_PARAMS: QueryParamsConfig = {
    selectedTab: { name: 'tab', type: 'string' },
    selectedTerritories: { name: 'territories', type: 'string' },
    selectedService: { name: 'service', type: 'string' },
    selectedPolicy: { name: 'policy', type: 'string' },
};

export interface RulesRouteParams {
    selectedTab: string;
    selectedTerritories: string;
    selectedService: string;
    selectedPolicy: string;
}

const SERVICE_OPTIONS = [
    {
        value: TIKTOK_VALUE,
        label: 'TikTok',
    },
    {
        value: YOUTUBE_VALUE,
        label: 'YouTube',
    },
];

const BASE_POLICY_OPTIONS: PolicyFilter[] = [
    {
        value: PolicyType['monetize'],
        label: PolicyType['monetize'],
    },
    {
        value: PolicyType['block_access'],
        label: PolicyType['block_access'],
    },
    {
        value: PolicyType['carveout'],
        label: PolicyType['carveout'],
    },
];
const LEVEL_OPTIONS = [
    {
        value: 'Account',
        label: 'Account',
    },
    {
        value: 'Subaccount',
        label: 'Subaccount',
    },
    {
        value: 'Track',
        label: 'Track',
    },
];

export const enum TimeRule {
    active,
    scheduled,
    expired,
}

export interface Territory {
    territoryCodeA2: string;
    territoryName: string;
    continent: string;
}

interface LevelFilter {
    label: string;
    value: string;
}

interface Filter {
    countries: string[];
    service?: ServiceFilter[];
    policy?: PolicyFilter;
    level?: LevelFilter;
    timeRule: TimeRule;
}

interface DeliveryRule {
    countryName: string | undefined;
    active: boolean;
    policy: string;
    service: string;
    territory: string;
    startDate?: string | undefined;
    endDate?: string | undefined;
    createdDate: string;
    lastModifiedDate: string;
    createdBy: Profile;
    lastModifiedBy: Profile;
    level: string;
}

interface FormattedRules {
    currentRules: DeliveryRule[];
    scheduledRules: DeliveryRule[];
    expiredRules: DeliveryRule[];
}

interface Props {
    track: FormattedTrack;
    territories: Territories;
    audioAttributes: AudioAttributes;
    rightsAttributes: RightsAttributes;
    handleReload: (shouldReload: boolean) => void;
}

const formatDeliveryRules = (
    vendorRules: FingerprintRule[],
    subaccountRules: FingerprintRule[],
    trackRules: FingerprintRule[],
    territories: Territory[] | undefined,
    filter: Filter,
    isYoutubeFingerprintRules: boolean,
    showCustomPolicies: boolean
): FormattedRules => {
    if (territories) {
        const formattedVendorRules = vendorRules.map(rule => {
            if (rule.territory == '*')
                return {
                    ...rule,
                    service: rule.service == '*' ? GLOBAL_TITLE : rule.service,
                    countryName: GLOBAL_TITLE,
                    territory: GLOBAL_CODE,
                    level: 'Account',
                };

            const foundCountry = territories.find(
                (t: Territory) => t.territoryCodeA2 === rule.territory
            );
            return {
                ...rule,
                service: rule.service == '*' ? GLOBAL_TITLE : rule.service,
                countryName: foundCountry?.territoryName,
                level: 'Account',
            };
        });
        const formattedSubaccountRules = subaccountRules.map(rule => {
            if (rule.territory == '*')
                return {
                    ...rule,
                    service: rule.service == '*' ? GLOBAL_TITLE : rule.service,
                    countryName: GLOBAL_TITLE,
                    territory: GLOBAL_CODE,
                    level: 'Subaccount',
                };

            const foundCountry = territories.find(
                (t: Territory) => t.territoryCodeA2 === rule.territory
            );
            return {
                ...rule,
                service: rule.service == '*' ? GLOBAL_TITLE : rule.service,
                countryName: foundCountry?.territoryName,
                level: 'Subaccount',
            };
        });
        const formattedTrackRules = trackRules.map(rule => {
            if (rule.territory == '*')
                return {
                    ...rule,
                    service: rule.service == '*' ? GLOBAL_TITLE : rule.service,
                    countryName: GLOBAL_TITLE,
                    territory: GLOBAL_CODE,
                    level: 'Track',
                };

            const foundCountry = territories.find(
                (t: Territory) => t.territoryCodeA2 === rule.territory
            );
            return {
                ...rule,
                service: rule.service == '*' ? GLOBAL_TITLE : rule.service,
                countryName: foundCountry?.territoryName,
                level: 'Track',
            };
        });
        const formattedRules = formattedVendorRules.concat(
            formattedSubaccountRules,
            formattedTrackRules
        );

        if (formattedRules.length == 0) {
            return {
                currentRules: [],
                scheduledRules: [],
                expiredRules: [],
            };
        }
        let filteredRules = formattedRules;
        const foundGlobalCountry = filter.countries.find(
            country => country === GLOBAL_CODE
        );
        if (
            filter.countries.length &&
            !foundGlobalCountry &&
            filter.countries.length < ALL_COUNTRIES_LENGTH
        ) {
            filteredRules = filteredRules.filter(rule => {
                const foundCountry = filter.countries.find(
                    country => country === rule.territory
                );
                if (foundCountry) return rule;
            });
        }
        if (
            filter.service?.length &&
            !filter.service.some(s => s.value === '*')
        ) {
            const serviceValues = filter.service.map(s => s.value);
            filteredRules = filteredRules.filter(rule =>
                serviceValues.includes(rule.service)
            );
        } else {
            // do not show Meta service if "All Services" is selected
            filteredRules = filteredRules.filter(
                rule => rule.service !== META_VALUE
            );

            if (!isYoutubeFingerprintRules) {
                // do not show YouTube if FF is off
                filteredRules = filteredRules.filter(
                    rule => rule.service !== YOUTUBE_VALUE
                );
            }
        }

        if (!showCustomPolicies) {
            filteredRules = filteredRules.filter(rule =>
                [
                    PolicyType.monetize,
                    PolicyType.block_access,
                    PolicyType.carveout,
                ].includes(rule.policy as PolicyType)
            );
        }

        if (filter.policy)
            filteredRules = filteredRules.filter(
                rule => rule.policy === filter.policy?.value
            );
        if (filter.level)
            filteredRules = filteredRules.filter(
                rule => rule.level === filter.level?.value
            );

        const filteredCurrentRules = filteredRules.filter(rule => {
            if (rule.policy == PolicyType['carveout']) return rule;

            if (rule.startDate && new Date(rule.startDate) <= new Date()) {
                if (
                    rule.endDate &&
                    (rule.endDate == '-' || new Date(rule.endDate) > new Date())
                ) {
                    return rule;
                }
            }
        });
        return {
            currentRules: filteredCurrentRules,
            scheduledRules: filteredRules.filter(
                rule => rule.startDate && new Date(rule.startDate) > new Date()
            ),
            expiredRules: filteredRules.filter(
                rule => rule.endDate && new Date(rule.endDate) < new Date()
            ),
        };
    }

    return {
        currentRules: [],
        scheduledRules: [],
        expiredRules: [],
    };
};

const RulesView: FC<Props> = ({
    track,
    territories,
    audioAttributes,
    rightsAttributes,
    handleReload,
}) => {
    const isYoutubeFingerprintRules = useDisplayYoutubeFingerprintRulesFF();
    const showCustomPolicies = useShowCustomPoliciesFF();
    const policyOptions = showCustomPolicies
        ? [
              ...BASE_POLICY_OPTIONS,
              {
                  value: PolicyType['sixtyseconds'],
                  label: PolicyType['sixtyseconds'],
              },
          ]
        : BASE_POLICY_OPTIONS;
    const [params, setUrlParams] = useRouteParams<RulesRouteParams>(
        ROUTE_CATALOG_TRACK,
        {
            queryParams: PAGE_QUERY_PARAMS,
        }
    );

    const territoriesFilter =
        params.selectedTerritories && params.selectedTerritories !== GLOBAL_CODE
            ? params.selectedTerritories?.split('-')
            : [];
    const servicesFilter =
        isYoutubeFingerprintRules && params.selectedService
            ? params.selectedService.split(',').map(service => ({
                  label: service,
                  value: service,
              }))
            : undefined;
    const policiesFilter = params.selectedPolicy
        ? {
              label: params.selectedPolicy,
              value: params.selectedPolicy,
          }
        : undefined;

    const {
        vendorRules,
        subaccountRules,
        rules,
        tuid,
        audioAttributes: trackAudioAttributes,
        rightsAttributes: trackRightsAttributes,
        fingerprintRights,
    } = track;

    const [updateCallback] = useSetFingerprintRulesForTrackMutation();
    const [updateAudioAttrCallback] = useSetAudioAttributesMutation();
    const [updateRightsAttrCallback] = useSetRightsAttributesMutation();

    const [countryFilter, setCountryFilter] = useState(territoriesFilter);
    const [serviceFilter, setServiceFilter] = useState<
        ServiceFilter[] | undefined
    >(servicesFilter);
    const [policyFilter, setPolicyFilter] = useState<PolicyFilter | undefined>(
        policiesFilter
    );
    const [levelFilter, setLevelFilter] = useState<LevelFilter | undefined>(
        undefined
    );
    const [timeRuleFilter, setTimeRuleFilter] = useState<TimeRule>(
        TimeRule.active
    );
    const [openAddRuleSidecar, setOpenAddRuleSidecar] = useState(false);
    const [openAttributeSidecar, setOpenAttributeSidecar] = useState(false);
    const [editMessage, setEditMessage] = useState('');

    const dropdownCountries =
        territories?.map(country => ({
            value: country.territoryCodeA2,
            continent: country.continent,
        })) ?? [];

    const handleCountryChange = (events: CountryOption[]) => {
        if (events.length === 0) {
            setUrlParams({
                selectedTerritories: '',
            });
            return setCountryFilter([]);
        }
        setUrlParams({
            selectedTerritories: events.map(f => f.value).join('-'),
        });
        setCountryFilter(events.map(e => e.value));
    };

    const handlePolicyChange = (
        event: { value: string; label: string } | undefined
    ) => {
        setUrlParams({
            selectedPolicy: event?.value,
        });
        setPolicyFilter(event);
    };

    const handleServiceChange = (
        event: { value: string; label: string }[] | undefined
    ) => {
        setUrlParams({
            selectedService: event?.map(f => f.value).join(','),
        });
        setServiceFilter(event);
    };

    const handleSaveRule = (
        rules: FingerprintRuleInput[],
        timeFiler: TimeRule | null,
        message?: string
    ) => {
        updateCallback({
            variables: {
                id: String(tuid),
                rules: JSON.parse(JSON.stringify(rules)),
            },
        }).catch(e => console.log(e));
        const messageToUse = message
            ? message
            : $t('digitalProducts.rulesView.defaultCreateToast');

        setCountryFilter([]);
        setServiceFilter(
            isYoutubeFingerprintRules ? undefined : [SERVICE_OPTIONS[0]]
        );
        setPolicyFilter(undefined);
        setLevelFilter(undefined);
        setEditMessage(messageToUse);

        setUrlParams({
            selectedTerritories: undefined,
            selectedService: undefined,
            selectedPolicy: undefined,
        });

        closeAddRuleSidecar();
        setTimeout(() => {
            setEditMessage('');
        }, 5500);

        // the comparison with `null` should be explicit,
        // as timeFilter could be `0` — which equals FALSE
        if (timeFiler !== null) setTimeRuleFilter(timeFiler);
    };

    const handleDeleteRule = (
        message: string,
        rules: FingerprintRuleInput[]
    ) => {
        updateCallback({
            variables: {
                id: String(tuid),
                rules: JSON.parse(JSON.stringify(rules)),
            },
        }).catch(e => console.log(e));
        setEditMessage(message);
        setTimeout(() => {
            setEditMessage('');
        }, 5500);
    };

    const handleSaveAttributes = (
        audioAttrIds: string[],
        rightsAttrIds: string[]
    ) => {
        handleReload(true);
        updateAudioAttrCallback({
            variables: {
                input: [
                    {
                        tuid,
                        audioAttributeIds: audioAttrIds,
                    },
                ],
            },
        }).catch(e => console.log(e));

        updateRightsAttrCallback({
            variables: {
                input: [
                    {
                        tuid,
                        rightsAttributeIds: rightsAttrIds,
                    },
                ],
            },
        }).catch(e => console.log(e));

        closeAttributeSidecar();

        setTimeout(() => {
            handleReload(false);
        }, 1500);
    };

    const closeAddRuleSidecar = () => {
        setOpenAddRuleSidecar(false);
    };

    const closeAttributeSidecar = () => {
        setOpenAttributeSidecar(false);
    };

    const filter = {
        countries: countryFilter,
        policy: policyFilter,
        service: serviceFilter,
        level: levelFilter,
        timeRule: timeRuleFilter,
    };
    const formattedRules = formatDeliveryRules(
        vendorRules,
        subaccountRules,
        rules,
        territories,
        filter,
        isYoutubeFingerprintRules,
        showCustomPolicies
    );

    let tableRulesToUse;
    if (timeRuleFilter === TimeRule.active)
        tableRulesToUse = formattedRules.currentRules;
    else if (timeRuleFilter === TimeRule.scheduled)
        tableRulesToUse = formattedRules.scheduledRules;
    else if (timeRuleFilter === TimeRule.expired)
        tableRulesToUse = formattedRules.expiredRules;
    else tableRulesToUse = formattedRules.currentRules;

    const isEmptyDataState =
        !vendorRules.length && !subaccountRules.length && !rules.length;

    const renderAttributes = () => {
        return (
            <div className={`${CLASS_NAME}-attributes`}>
                <div className={`${CLASS_NAME}-attributes-action`}>
                    <div className={`${CLASS_NAME}-attributes-action-title`}>
                        <h2>
                            {$t('digitalProducts.rulesView.attributes.title')}
                        </h2>
                        <p
                            className={`${CLASS_NAME}-attributes-action-subtitle`}
                        >
                            {$t(
                                'digitalProducts.rulesView.attributes.subTitle'
                            )}
                        </p>
                    </div>
                    <div className={`${CLASS_NAME}-attributes-action-edit`}>
                        <GlyphButton
                            variant="secondary"
                            name="edit"
                            id="btn-attributes"
                            data-testid="btn-attributes"
                            onClick={() => setOpenAttributeSidecar(true)}
                            disabled={!permissionToManageRules}
                        />
                    </div>
                </div>
                <div className={`${CLASS_NAME}-attributes-data`}>
                    <div>
                        <Label
                            text={$t(
                                'digitalProducts.rulesView.attributes.audioTitle'
                            )}
                        />
                        <div className={`${CLASS_NAME}-attributes-data-tags`}>
                            {trackAudioAttributes.length === 0 && EMPTY_CHAR}
                            {trackAudioAttributes.map(aa => (
                                <Tag key={`${tuid}-${aa}`} text={aa} />
                            ))}
                        </div>
                    </div>
                    <div>
                        <Label
                            text={$t(
                                'digitalProducts.rulesView.attributes.rightsTitle'
                            )}
                        />
                        <div className={`${CLASS_NAME}-attributes-data-tags`}>
                            {trackRightsAttributes.length === 0 && EMPTY_CHAR}
                            {trackRightsAttributes.map(aa => (
                                <Tag key={`${tuid}-${aa}`} text={aa} />
                            ))}
                        </div>
                    </div>
                    <div>
                        <Label
                            text={$t(
                                'digitalProducts.rulesView.attributes.fingerprintRightsTitle'
                            )}
                        />
                        <p
                            className={`${CLASS_NAME}-attributes-data-fingerprint-rights`}
                        >
                            {fingerprintRights}
                        </p>
                    </div>
                </div>
            </div>
        );
    };
    const renderSegmentedFilterBtnText = (
        testId: string,
        id: TimeRule,
        disabled: boolean,
        text: string,
        tooltipMessage: string
    ) => {
        if (disabled)
            return (
                <Tooltip message={tooltipMessage} id={`${id}-tooltip`}>
                    <SegmentedButton.Text
                        testId={testId}
                        id={id}
                        disabled={disabled}
                    >
                        {text}
                    </SegmentedButton.Text>
                </Tooltip>
            );
        return (
            <SegmentedButton.Text testId={testId} id={id} disabled={disabled}>
                {text}
            </SegmentedButton.Text>
        );
    };

    const { roles } = useIdentity();

    const permissionToManageRules = canManageRules(roles || []);

    return (
        <div className={CLASS_NAME}>
            {renderAttributes()}
            <div className={`${CLASS_NAME}-rule-section-title`}>
                <div className={`${CLASS_NAME}-rule-section-title-left`}>
                    <h2>{$t('digitalProducts.rulesView.ruleSectionTitle')}</h2>
                    <p className={`${CLASS_NAME}-rule-section-subtitle`}>
                        {$t('digitalProducts.rulesView.ruleSectionSubTitle')}
                    </p>
                </div>

                <div className={`${CLASS_NAME}-rule-section-title-right`}>
                    <Button
                        className={`${CLASS_NAME}-rule-section-title-right-button`}
                        onClick={() => setOpenAddRuleSidecar(true)}
                        data-testid="btn-add-rule"
                        disabled={!permissionToManageRules}
                    >
                        {$t('digitalProducts.rulesView.buttons.addRule')}
                    </Button>
                </div>
            </div>
            {isEmptyDataState ? (
                <div className={`${CLASS_NAME}-empty-state`}>
                    <Section>
                        <Section.Body>
                            <InfoMessage
                                message={$t(
                                    'digitalProducts.rulesView.emptyState.title'
                                )}
                                size="sm"
                                body={$t(
                                    'digitalProducts.rulesView.emptyState.subTitle'
                                )}
                            />
                        </Section.Body>
                    </Section>
                </div>
            ) : (
                <div className={`${CLASS_NAME}-data`}>
                    <div className={`${CLASS_NAME}-filters`}>
                        <div>
                            <SegmentedButton
                                variant="primary"
                                onChange={setTimeRuleFilter}
                                defaultValue={timeRuleFilter}
                                value={timeRuleFilter}
                            >
                                {renderSegmentedFilterBtnText(
                                    'btn-active',
                                    TimeRule.active,
                                    !formattedRules.currentRules.length,
                                    $t(
                                        'digitalProducts.rulesView.filters.active'
                                    ),
                                    $t(
                                        'digitalProducts.rulesView.filters.emptyActive'
                                    )
                                )}
                                {renderSegmentedFilterBtnText(
                                    'btn-scheduled',
                                    TimeRule.scheduled,
                                    !formattedRules.scheduledRules.length,
                                    $t(
                                        'digitalProducts.rulesView.filters.scheduled'
                                    ),
                                    $t(
                                        'digitalProducts.rulesView.filters.emptyScheduled'
                                    )
                                )}
                                {renderSegmentedFilterBtnText(
                                    'btn-expired',
                                    TimeRule.expired,
                                    !formattedRules.expiredRules.length,
                                    $t(
                                        'digitalProducts.rulesView.filters.expired'
                                    ),
                                    $t(
                                        'digitalProducts.rulesView.filters.emptyExpired'
                                    )
                                )}
                            </SegmentedButton>
                        </div>
                        <div className={`${CLASS_NAME}-filters-right`}>
                            <Select
                                className={`${CLASS_NAME}-filters-right-dropdown-level`}
                                defaultValue={undefined}
                                selectedValue={levelFilter}
                                options={LEVEL_OPTIONS}
                                onChange={setLevelFilter}
                                testId="dpd-level"
                                placeholder="Rule Level"
                                compact
                                hideFilter
                            />
                            <Select
                                className={`${CLASS_NAME}-filters-right-dropdown-policy`}
                                selectedValue={policyFilter}
                                options={policyOptions}
                                onChange={handlePolicyChange}
                                testId="dpd-policy"
                                placeholder="Rule"
                                compact
                                hideFilter
                            />
                            <MarketSelector
                                className={`${CLASS_NAME}-filters-right-dropdown-country`}
                                selectedValue={countryFilter}
                                onChange={handleCountryChange}
                                countries={dropdownCountries}
                                testId="dpd-country"
                                variant="compact"
                                placeholder="Country"
                                sectionGroupSelect
                            />
                            {isYoutubeFingerprintRules && (
                                <MultiSelect
                                    className={`${CLASS_NAME}-filters-right-dropdown-service`}
                                    selectedValue={serviceFilter}
                                    options={SERVICE_OPTIONS}
                                    onChange={handleServiceChange}
                                    testId="dpd-service"
                                    placeholder="Service"
                                    compact
                                    hideFilter
                                />
                            )}
                        </div>
                    </div>
                    <DeliverySummary
                        track={track}
                        timeRuleFilter={timeRuleFilter}
                    />
                    <div>
                        <DeliveryRulesTable
                            accountType="Track"
                            tableRules={tableRulesToUse}
                            higherLevelRules={vendorRules.concat(
                                subaccountRules
                            )}
                            currentRules={rules}
                            current
                            scheduled={false}
                            expired={false}
                            onDeleteRow={handleDeleteRule}
                            onEditRow={handleSaveRule}
                            territories={territories}
                            canManageRules={permissionToManageRules}
                        />
                    </div>
                </div>
            )}
            {permissionToManageRules && (
                <UpdatedAddRule
                    title={$t('digitalProducts.rulesView.sidecar.title')}
                    isOpen={openAddRuleSidecar}
                    onClose={closeAddRuleSidecar}
                    territories={territories}
                    currentRules={rules}
                    onConfirm={handleSaveRule}
                    higherLevelRules={vendorRules.concat(subaccountRules)}
                />
            )}
            {permissionToManageRules && (
                <AddAttribute
                    isOpen={openAttributeSidecar}
                    onClose={closeAttributeSidecar}
                    onConfirm={handleSaveAttributes}
                    trackAudioAttributes={trackAudioAttributes}
                    trackRightsAttributes={trackRightsAttributes}
                    audioAttributes={audioAttributes}
                    rightsAttributes={rightsAttributes}
                />
            )}
            {editMessage && (
                <ToastContainer
                    messages={[{ id: '1', content: editMessage }]}
                    toastTime={5000}
                />
            )}
        </div>
    );
};

export default RulesView;
