import React, { useEffect, useState } from 'react';
import { Field, MultiSelect } from '@theorchard/suite-components';
import { useProductSearch } from 'src/apollo/queries/product-search';
import { useTrackSearchByLabelIds } from 'src/apollo/queries/track-search';
import type { GetTracksByLabelIdsQuery } from 'src/apollo/queries/track-search/__generated__/get-tracks-by-label-ids';
import type { AttachmentDetail } from 'src/components/contract-detail/contract-terms-detail-presentational';
import type { AbacusContractTermsInputErrors } from 'src/types/abacus-contract-terms-distro-input-errors';

export interface ContractTermsDistroAttachmentsSelectProps {
    labelId: number | undefined;
    // eslint-disable-next-line no-unused-vars
    onOptionsChange?: (tracks: string[]) => void;
    initialOptions?: AttachmentDetail[];
    termType: string;
    errors: AbacusContractTermsInputErrors;
}

type TrackByLabelId = NonNullable<
    GetTracksByLabelIdsQuery['trackSearch']
>['tracks'][0];

interface Option {
    label: string;
    subtitle: string;
    value: string;
    key: string;
}

const dedupeTracks = (tracks: TrackByLabelId[]) => {
    const trackMap = new Map();

    tracks.forEach((track: TrackByLabelId) => {
        const isrc = track.isrc;
        const globalParticipants =
            track?.isrcInfo?.globalSoundRecording?.globalParticipants ?? [];
        const hasParticipants = globalParticipants.length > 0;

        if (!trackMap.has(isrc)) {
            trackMap.set(isrc, track);
        } else {
            const existing = trackMap.get(isrc);
            const existingHasParticipants =
                existing?.isrcInfo?.globalSoundRecording?.globalParticipants
                    ?.length > 0;

            if (hasParticipants && !existingHasParticipants) {
                trackMap.set(isrc, track);
            }
        }
    });

    return [...trackMap.values()];
};

export const ContractTermsDistroAttachmentsSelect: React.FC<
    ContractTermsDistroAttachmentsSelectProps
> = ({ labelId, onOptionsChange, initialOptions, termType }) => {
    const getTracks = useTrackSearchByLabelIds();
    const getProducts = useProductSearch();
    const [selectedOptions, setSelectedOptions] = useState<Option[]>([]);
    const DEFAULT_LIMIT = 500;
    const DEFAULT_OFFSET = 0;

    const formatTracks = (tracks: TrackByLabelId[]): Option[] => {
        const uniqueTracks = dedupeTracks(tracks);
        return (
            uniqueTracks
                .map((track: TrackByLabelId, idx: number) => {
                    if (
                        track.isrcInfo?.globalSoundRecording &&
                        track.isrcInfo?.globalSoundRecording?.globalParticipants
                            .length > 0
                    ) {
                        return {
                            label: `${track.name ?? ''} - ${track.isrc ?? ''}`,
                            value: track.isrc ?? '',
                            subtitle:
                                track.isrc +
                                ' - ' +
                                track.isrcInfo?.globalSoundRecording
                                    ?.globalParticipants[0].name,
                            key: `${track.isrc}___${idx}`,
                        };
                    } else {
                        return {
                            label: `${track.name ?? ''} - ${track.isrc ?? ''}`,
                            value: track.isrc ?? '',
                            subtitle: track.isrc + ' - ' + 'Unknown Artist',
                            key: `${track.isrc}___${idx}`,
                        };
                    }
                })
                .filter(
                    item =>
                        selectedOptions
                            .map(item => item.value)
                            .includes(item.value) === false
                ) ?? []
        );
    };

    const formatProducts = (products: any[]): Option[] => {
        return (
            products
                ?.map((product, idx) => {
                    if (product.labelParticipations.length > 0) {
                        return {
                            label: `${product.productName ?? ''} - ${product.upc ?? ''}`,
                            value: product.upc ?? '',
                            subtitle:
                                product.upc +
                                ' - ' +
                                product.labelParticipations[0].labelParticipant
                                    ?.name,
                            key: `${product.upc}___${idx}`,
                        };
                    }
                    return {
                        label: `${product.productName ?? ''} - ${product.upc ?? ''}`,
                        value: product.upc ?? '',
                        subtitle: product.upc + ' - ' + 'Unknown Artist',
                        key: `${product.upc}___${idx}`,
                    };
                })
                .filter(
                    item =>
                        selectedOptions
                            .map(item => item.value)
                            .includes(item.value) === false
                ) ?? []
        );
    };

    const onLoadOptionsHandler = async (term?: string) => {
        if (!term) return { data: [] };
        if (termType === 'track') {
            const tracks = await getTracks(
                term,
                [labelId ?? 0],
                DEFAULT_LIMIT,
                DEFAULT_OFFSET
            );
            return { data: formatTracks(tracks) };
        } else if (termType === 'product') {
            const products = await getProducts(
                term,
                labelId ? [labelId] : undefined,
                DEFAULT_LIMIT,
                DEFAULT_OFFSET
            );
            return { data: products ? formatProducts(products) : [] };
        } else {
            return { data: [] };
        }
    };

    useEffect(() => {
        if (!labelId) {
            setSelectedOptions([]);
            return;
        }
        setSelectedOptions(
            initialOptions?.map((option, idx) => ({
                label: `${option.name ?? ''} - ${option.value ?? ''}`,
                subtitle: option.artistName || '',
                value: option.value,
                key: `${option.value}___${idx}`,
            })) || []
        );
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [labelId, termType]);

    const handleChange = (selected: Option[]) => {
        setSelectedOptions(selected);
        // note: we use the value with '___' to ensure uniqueness it is not part of the final value
        onOptionsChange?.(selected.map(option => option.value.split('___')[0]));
    };

    return (
        <Field
            controlId="ContractTermsDistroAttachmentsSelect"
            labelText={termType === 'track' ? 'Tracks' : 'Products'}
            testId="ContractTermsDistroAttachmentsSelect"
            isOptional={true}
        >
            <MultiSelect<Option>
                key={labelId?.toString() || ''}
                className="ContractTermsDistroFormFields-TextInput"
                name="tracks"
                optionsMatchBy="all"
                options={selectedOptions}
                onLoadOptions={onLoadOptionsHandler}
                placeholder={
                    termType === 'track'
                        ? 'Search for track(s) or artist(s)'
                        : 'Search for product(s) or artist(s)'
                }
                onChange={handleChange}
                menuWidth="100%"
                disabled={!labelId}
                selectedValue={selectedOptions}
            />
        </Field>
    );
};
