import React, { useEffect, useMemo, useState } from 'react';
import {
    Button,
    Field,
    Form,
    MultiSelect,
    PageHeader,
    Radio,
    Section,
} from '@theorchard/suite-components';
import { GlyphIcon } from '@theorchard/suite-icons';
import sortBy from 'lodash-es/sortBy';
import { TransactionTypeGroupAdmin } from 'src/apollo/definitions/globalTypes';
import { useStoreList } from 'src/apollo/queries/stores';
import {
    useTransactionTypeGroups,
    useTransactionTypes,
} from 'src/apollo/queries/transaction-types';
import { ContractTermConditionsList } from 'src/components/contract-terms-form/contract-term-conditions-list';
import { ContractTermContext } from 'src/contexts/contract-term-context';
import type { AbacusDistroContractTermCondition } from 'src/types/abacus-contract-term';
import type { ProjectOption } from '../types';
import { buildDispatch } from './term-dispatch';
import type { TransferTermDraft } from './term-dispatch';

export type { TransferTermDraft } from './term-dispatch';
export { buildDispatch } from './term-dispatch';

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

export type TermsMode = 'label' | 'custom';

interface SetupTermsStepProps {
    // The product/track tree is only needed to populate the custom-term
    // dropdowns; a label-mode transfer (the default) works without it, and it
    // may still be loading or absent, so it is optional here.
    project: ProjectOption | undefined;
    terms: TransferTermDraft[];
    termsMode: TermsMode;
    onTermsChange: React.Dispatch<React.SetStateAction<TransferTermDraft[]>>;
    onTermsModeChange: (mode: TermsMode) => void;
}

const generateId = () =>
    typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
        ? crypto.randomUUID()
        : `id-${Date.now()}-${Math.random().toString(36).slice(2)}`;

interface MultiDropdownProps {
    id: string;
    options: DropdownOption[];
    selected: string[];
    onChange: (values: string[]) => void;
    placeholder: string;
}

const MultiDropdown: React.FC<MultiDropdownProps> = ({
    id,
    options,
    selected,
    onChange,
    placeholder,
}) => (
    <MultiSelect
        name={id}
        options={options}
        selectedValue={options.filter(o => selected.includes(o.value))}
        onChange={items => onChange(items ? items.map(i => i.value) : [])}
        placeholder={placeholder}
        portalElement={document.body}
    />
);

const newCondition = (termId: string): AbacusDistroContractTermCondition => ({
    contractTermConditionId: null,
    contractTermConditionName: null,
    contractTermId: termId,
    priority: 1,
    termRate: null,
    conditions: { countries: [], stores: [], transactionTypes: [] },
});

const SetupTermsStep: React.FC<SetupTermsStepProps> = ({
    project,
    terms,
    termsMode,
    onTermsChange,
    onTermsModeChange,
}) => {
    const { data: storesData } = useStoreList();
    const { data: transactionTypeData } = useTransactionTypes();
    const { data: transactionTypeGroupData } = useTransactionTypeGroups(
        TransactionTypeGroupAdmin.CONTRACT_ADMIN
    );

    const stores = useMemo(
        () =>
            sortBy(
                (storesData?.deliveryStoresV2?.items ?? []).map(
                    ({ id, name }: { id: string; name: string }) => ({
                        label: name,
                        value: id,
                    })
                ),
                ['label']
            ),
        [storesData]
    );

    const transactionTypes = useMemo(
        () =>
            sortBy(
                (transactionTypeData?.transactionTypes ?? []).map(
                    ({
                        txnTypeCode,
                        txnTypeName,
                        txnTypeId,
                    }: {
                        txnTypeCode: string;
                        txnTypeName: string;
                        txnTypeId: string;
                    }) => ({
                        label: `${txnTypeCode} - ${txnTypeName}`,
                        value: txnTypeId,
                    })
                ),
                ['label']
            ),
        [transactionTypeData]
    );

    const transactionTypeGroups = useMemo(
        () =>
            (transactionTypeGroupData?.transactionTypeGroups ?? []).map(
                ({
                    transactionTypeGroupName,
                    transactionTypes: tts,
                }: {
                    transactionTypeGroupName: string;
                    transactionTypes: { txnTypeId: string }[];
                }) => ({
                    transactionTypeGroupName,
                    transactionTypeIds: tts.map(tt => tt.txnTypeId),
                })
            ),
        [transactionTypeGroupData]
    );

    const productTerms = terms.filter(t => t.type === 'PRODUCT');
    const trackTerms = terms.filter(t => t.type === 'TRACK');

    // The Product/Track cards are collapsible. Track their open state so adding
    // a term can spring a collapsed card back open.
    const [productExpanded, setProductExpanded] = useState(true);
    const [trackExpanded, setTrackExpanded] = useState(true);

    // After a term is added, focus its name field so the user can start typing.
    const [focusTermId, setFocusTermId] = useState<string | null>(null);
    useEffect(() => {
        if (!focusTermId) return;
        const el = document.getElementById(`${focusTermId}-name`);
        if (el) {
            el.focus();
            setFocusTermId(null);
        }
    }, [focusTermId, terms]);

    const upcs = project?.upcs ?? [];

    const upcOptions: DropdownOption[] = upcs.map(u => ({
        label: `${u.productName} (${u.upc})`,
        value: u.upc,
    }));

    const trackOptions: DropdownOption[] = upcs.flatMap(u =>
        u.tracks.map(t => ({
            label: `${t.title} - ${t.isrc}`,
            value: t.isrc,
        }))
    );

    const updateTerm = (id: string, changes: Partial<TransferTermDraft>) =>
        onTermsChange(terms.map(t => (t.id === id ? { ...t, ...changes } : t)));

    const removeTerm = (id: string) =>
        onTermsChange(terms.filter(t => t.id !== id));

    const addTerm = (type: 'PRODUCT' | 'TRACK') => {
        const termId = generateId();
        onTermsChange([
            ...terms,
            {
                id: termId,
                type,
                name: type === 'PRODUCT' ? 'Product' : 'Track',
                attachments: [],
                conditions: [newCondition(termId)],
            },
        ]);
        if (type === 'PRODUCT') setProductExpanded(true);
        else setTrackExpanded(true);
        setFocusTermId(termId);
    };

    const handleTermsModeChange = (mode: TermsMode) => {
        onTermsModeChange(mode);
        if (mode === 'label') onTermsChange([]);
    };

    const termCountLabel = (n: number, noun: string) =>
        `${n} ${noun}${n === 1 ? '' : 's'}`;

    const renderTermEntry = (
        term: TransferTermDraft,
        attachmentOptions: DropdownOption[],
        index: number
    ) => {
        const isProduct = term.type === 'PRODUCT';
        const contextState = {
            conditions: term.conditions,
            contractTermId: term.id,
            transactionTypes,
            transactionTypeGroups,
            stores,
            deletedConditions: [],
            countryCodes: [],
            errors: [],
        };
        const dispatch = buildDispatch(term.id, onTermsChange);

        return (
            <Section key={term.id} level="sub" className="SetupTermsStep-term">
                <Section.Header
                    title={`${isProduct ? 'Product Term' : 'Track Term'} ${index}`}
                >
                    <Button
                        glyph
                        variant="secondary"
                        data-testid={`deleteTerm-${term.id}`}
                        aria-label={`Delete ${isProduct ? 'product' : 'track'} term ${index}`}
                        onClick={() => removeTerm(term.id)}
                    >
                        <GlyphIcon name="trash" size={16} />
                    </Button>
                </Section.Header>
                <Section.Body>
                    <Form.Group>
                        <Field
                            controlId={`${term.id}-name`}
                            labelText="Term Name"
                        >
                            <Form.Control
                                id={`${term.id}-name`}
                                type="text"
                                value={term.name}
                                placeholder={
                                    isProduct
                                        ? 'e.g. Greatest Hits Override'
                                        : 'e.g. NR Track Override'
                                }
                                onChange={(
                                    e: React.ChangeEvent<HTMLInputElement>
                                ) =>
                                    updateTerm(term.id, {
                                        name: e.target.value,
                                    })
                                }
                            />
                        </Field>
                    </Form.Group>

                    <Form.Group>
                        <Field
                            controlId={`${term.id}-attachments`}
                            labelText={
                                isProduct ? 'Products (UPC)' : 'Tracks (ISRC)'
                            }
                        >
                            <MultiDropdown
                                id={`${term.id}-attachments`}
                                options={attachmentOptions}
                                selected={term.attachments}
                                onChange={values =>
                                    updateTerm(term.id, { attachments: values })
                                }
                                placeholder={
                                    isProduct
                                        ? 'Select products'
                                        : 'Select tracks'
                                }
                            />
                        </Field>
                    </Form.Group>

                    <ContractTermContext.Provider
                        value={{ state: contextState, dispatch }}
                    >
                        <ContractTermConditionsList
                            portalElement={document.body}
                            newConditionLabel="+ NEW CONDITION"
                            showActionColumn
                            highlightInvalidRate
                        />
                    </ContractTermContext.Provider>
                </Section.Body>
            </Section>
        );
    };

    return (
        <div className="SetupTermsStep">
            <div className="CreateTransferForm-header">
                <PageHeader.Title className="CreateTransferForm-title">
                    Set up Terms
                </PageHeader.Title>
                <p className="CreateTransferForm-subtitle">
                    Choose how terms apply to the transferred products and
                    tracks
                </p>
            </div>
            <div className="SetupTermsStep-mode">
                <Form.Label>
                    Select your preferred method for managing terms
                </Form.Label>
                <Radio
                    id="terms-mode-label"
                    checked={termsMode === 'label'}
                    label="Apply Label Terms - the contract's label-level rate applies to all transferred products and tracks"
                    onChange={() => handleTermsModeChange('label')}
                    testId="terms-mode-label"
                />
                <Radio
                    id="terms-mode-custom"
                    checked={termsMode === 'custom'}
                    label="Configure specific Product and Track terms"
                    onChange={() => handleTermsModeChange('custom')}
                    testId="terms-mode-custom"
                />
            </div>

            {termsMode === 'custom' && (
                <>
                    <div
                        className="SetupTermsStep-subheading"
                        data-testid="configureTermsSubheading"
                    >
                        Configure specific Product and Track terms
                    </div>
                    <Section
                        expandable
                        expanded={productExpanded}
                        onExpand={setProductExpanded}
                        className="SetupTermsStep-card"
                    >
                        <Section.Header>
                            <div className="SetupTermsStep-cardHeader">
                                <div className="SetupTermsStep-cardHeader-titles">
                                    <Section.Title>Product Terms</Section.Title>
                                    <div className="SetupTermsStep-cardHeader-count text-muted">
                                        {termCountLabel(
                                            productTerms.length,
                                            'Product Term'
                                        )}
                                    </div>
                                </div>
                                <Button
                                    variant="secondary"
                                    data-testid="addProductTerm"
                                    onClick={() => addTerm('PRODUCT')}
                                >
                                    + ADD
                                </Button>
                            </div>
                        </Section.Header>
                        <Section.Body>
                            {productTerms.map((term, i) =>
                                renderTermEntry(term, upcOptions, i + 1)
                            )}
                        </Section.Body>
                    </Section>

                    <Section
                        expandable
                        expanded={trackExpanded}
                        onExpand={setTrackExpanded}
                        className="SetupTermsStep-card"
                    >
                        <Section.Header>
                            <div className="SetupTermsStep-cardHeader">
                                <div className="SetupTermsStep-cardHeader-titles">
                                    <Section.Title>Track Terms</Section.Title>
                                    <div className="SetupTermsStep-cardHeader-count text-muted">
                                        {termCountLabel(
                                            trackTerms.length,
                                            'Track Term'
                                        )}
                                    </div>
                                </div>
                                <Button
                                    variant="secondary"
                                    data-testid="addTrackTerm"
                                    onClick={() => addTerm('TRACK')}
                                >
                                    + ADD
                                </Button>
                            </div>
                        </Section.Header>
                        <Section.Body>
                            {trackTerms.map((term, i) =>
                                renderTermEntry(term, trackOptions, i + 1)
                            )}
                        </Section.Body>
                    </Section>
                </>
            )}
        </div>
    );
};

export default SetupTermsStep;
