import {
    Alert,
    Sidecar,
    Stepper,
    useToast,
} from '@theorchard/suite-components';
import { ENV_PROD, useAppConfig } from '@theorchard/suite-frontend';
import React, { useEffect, useState } from 'react';
import { useIsYouTubeFingerprintRulesEnabled } from 'shared/features';
import CountriesMultiSelect from 'src/components/countriesMultiSelect';
import ServicesMultiSelect from 'src/components/servicesMultiSelect';
import { defaultServiceValue } from 'src/components/servicesMultiSelect/services-multi-select';
import TracksMultiSelect from 'src/components/tracksMultiSelect';
import { useSetFingerprintRulesForTrackBulkMutation } from 'src/data/mutations';
import { useGetProductTracks, useTerritoriesQuery } from 'src/data/queries';
import { getTracksWithConflictingRules } from 'src/utils/validation';
import type { CountryOption, Step } from '@theorchard/suite-components';
import type { FC } from 'react';
import type { TerritoriesForTrackRulesQuery } from 'src/data/queries/territories/__generated__/territoriesForTrackRules';
import type { Track } from 'src/types';

const CLASS_NAME = 'AddFingerprintRestriction';
interface Props {
    productId: string;
    isOpen: boolean;
    onClose: () => void;
    onRulesUpdated: () => void;
}

const RULES_IN_BATCH_SIZE = 250;

const composeContentTrackUrl = (
    environment: string,
    productId: string,
    trackId: string
) => {
    let contentUrl = `https://content.qaorch.com/catalog/digital-audio/${productId}/track/${trackId}`;
    if (environment === ENV_PROD)
        contentUrl = `https://content.theorchard.com/catalog/digital-audio/${productId}/track/${trackId}`;

    return contentUrl;
};

const getTracksStepContent = (
    tracks: Track[],
    tracksLoading: boolean,
    setSelectedTracks: (tracks: Track[]) => void
) => {
    return (
        <div className={`${CLASS_NAME}-restriction-tracks`}>
            <TracksMultiSelect
                tracks={tracks}
                loading={tracksLoading}
                onApply={setSelectedTracks}
            />
        </div>
    );
};

const getCountriesStepContent = (
    territories: TerritoriesForTrackRulesQuery['territories'] | undefined,
    handleCountries: (countries: CountryOption[]) => void
) => {
    return (
        <div className={`${CLASS_NAME}-restriction-countries`}>
            <CountriesMultiSelect
                territories={territories}
                onApply={handleCountries}
            />
        </div>
    );
};

const getServicesStepContent = (
    setSelectedServices: React.Dispatch<React.SetStateAction<string[]>>
) => {
    return (
        <div className={`${CLASS_NAME}-restriction-services`}>
            <ServicesMultiSelect onApply={setSelectedServices} />
        </div>
    );
};

const AddFingerprintRestriction: FC<Props> = ({
    productId,
    isOpen,
    onClose,
    onRulesUpdated,
}) => {
    const isYouTubeFingerprintRulesEnabled =
        useIsYouTubeFingerprintRulesEnabled();
    const { environment } = useAppConfig();
    const toast = useToast();
    const [isSaveRulesError, setIsSaveRulesError] = useState<boolean>(false);
    const [trackWithRulesConflicts, setTrackWithRulesConflicts] = useState<
        Track[]
    >([]);
    const [selectedTracks, setSelectedTracks] = useState<Track[]>([]);
    const [selectedServices, setSelectedServices] = useState<string[]>(
        !isYouTubeFingerprintRulesEnabled ? [defaultServiceValue.value] : []
    );
    const [selectedCountries, setSelectedCountries] = useState<string[]>([]);
    const { loading: tracksLoading, data: tracks = [] } =
        useGetProductTracks(productId);

    const [updateTrackRulesMutation, { loading: loadingSetRules }] =
        useSetFingerprintRulesForTrackBulkMutation();

    const territoriesResult = useTerritoriesQuery();

    const handleCountries = (countries: CountryOption[]) => {
        setSelectedCountries(countries.map(c => c.value));
    };

    const showConfirmToast = () => {
        toast(
            <p>
                {$t(
                    'fingerprintRestrictions.fingerprintRestrictionsOaPanel.restrictionRulesAppliedTxt'
                )}
            </p>,
            { variant: 'success' }
        );
    };

    const handleConfirm = () => {
        const input = selectedTracks.map(t => ({
            id: t.tuid,
            rules: [
                ...t.rules.map(r => ({
                    policy: r.policy,
                    service: r.service,
                    territory: r.territory,
                    start: r.startDate,
                    end: r.endDate,
                })),
                ...selectedCountries.flatMap(country =>
                    selectedServices.map(service => ({
                        policy: 'carveout',
                        service,
                        territory: country,
                        start: null,
                        end: null,
                    }))
                ),
            ],
        }));

        const inputs = [];
        const inputSize = Math.floor(
            RULES_IN_BATCH_SIZE / selectedCountries.length
        );
        for (let i = 0; i < input.length; i += inputSize) {
            inputs.push(input.slice(i, i + inputSize));
        }

        Promise.all(
            inputs.map(input =>
                updateTrackRulesMutation({ variables: { input } })
            )
        )
            .then(() => {
                showConfirmToast();
                onClose();
                onRulesUpdated();
            })
            .catch(_ => {
                setIsSaveRulesError(true);
            });
    };

    useEffect(() => {
        if (
            selectedTracks.length > 0 &&
            selectedCountries.length > 0 &&
            selectedServices.length > 0
        )
            setTrackWithRulesConflicts(
                getTracksWithConflictingRules(
                    selectedTracks,
                    selectedCountries,
                    selectedServices
                )
            );

        if (
            (selectedTracks.length === 0 ||
                selectedCountries.length === 0 ||
                selectedServices.length === 0) &&
            trackWithRulesConflicts.length > 0
        )
            setTrackWithRulesConflicts([]);
    }, [
        selectedTracks,
        selectedCountries,
        selectedServices,
        trackWithRulesConflicts.length,
    ]);

    const isConfirmDisabled =
        territoriesResult.loading ||
        loadingSetRules ||
        trackWithRulesConflicts.length > 0 ||
        selectedTracks.length === 0 ||
        selectedCountries.length === 0 ||
        selectedServices.length === 0;

    const steps: Step[] = [
        {
            icon: {
                glyphIcon: 'circle',
                variant: 'neutral',
            },
            title: $t(
                'fingerprintRestrictions.addFingerprintRestriction.sidecar.trackTitle'
            ),
            body: getTracksStepContent(
                tracks,
                tracksLoading,
                setSelectedTracks
            ),
        },
        {
            icon: {
                glyphIcon: 'circle',
                variant: 'neutral',
            },
            title: $t(
                'fingerprintRestrictions.addFingerprintRestriction.sidecar.countryTitle'
            ),
            body: getCountriesStepContent(
                territoriesResult.data?.territories,
                handleCountries
            ),
        },
        {
            icon: {
                glyphIcon: 'circle',
                variant: 'neutral',
            },
            title: $t(
                'fingerprintRestrictions.addFingerprintRestriction.sidecar.servicesTitle'
            ),
            body: getServicesStepContent(setSelectedServices),
        },
    ];

    return (
        <Sidecar
            className={`${CLASS_NAME}-sidecar`}
            testId="sidecar"
            title={$t(
                'fingerprintRestrictions.addFingerprintRestriction.sidecar.title'
            )}
            isOpen={isOpen}
            onRequestClose={onClose}
            onConfirm={handleConfirm}
            confirmDisabled={isConfirmDisabled}
        >
            <div className={`${CLASS_NAME}-body`}>
                <div className={`${CLASS_NAME}-description`}>
                    {$t(
                        'fingerprintRestrictions.addFingerprintRestriction.sidecar.description'
                    )}
                </div>

                <Stepper layout="vertical" steps={steps} />

                {trackWithRulesConflicts.length > 0 && (
                    <Alert
                        className={`${CLASS_NAME}-conflict-alert`}
                        variant="error"
                        title={$t(
                            'fingerprintRestrictions.addFingerprintRestriction.sidecar.conflictTitle'
                        )}
                        text={
                            <span>
                                {$t(
                                    'fingerprintRestrictions.addFingerprintRestriction.sidecar.conflictText'
                                )}
                                <ul>
                                    {trackWithRulesConflicts.map(t => {
                                        return (
                                            <li key={t.tuid}>
                                                <a
                                                    href={composeContentTrackUrl(
                                                        environment,
                                                        productId,
                                                        t.tuid
                                                    )}
                                                >
                                                    {t.trackName}
                                                </a>
                                            </li>
                                        );
                                    })}
                                </ul>
                            </span>
                        }
                    />
                )}

                {isSaveRulesError && (
                    <Alert
                        className={`${CLASS_NAME}-conflict-alert`}
                        variant="error"
                        text={$t(
                            'fingerprintRestrictions.addFingerprintRestriction.sidecar.saveError'
                        )}
                    />
                )}
            </div>
        </Sidecar>
    );
};

export default AddFingerprintRestriction;
