import React, {
    type ChangeEventHandler,
    useContext,
    useEffect,
    useState,
} from 'react';
import { Col, Container, Label, Row } from '@theorchard/suite-components';
import { isEmpty } from 'lodash-es';
import { useParams } from 'react-router-dom';
import { useContractTerms } from 'src/apollo/queries/contract-term';
import ProductSearchableSelect from 'src/components/shared/product-searchable-select';
import {
    SET_CONTRACT_TERM_ATTACHMENTS,
    SET_DEFAULT_CONDITION,
    SET_ERRORS,
    CONTRACT_TERM_TYPES,
    PRODUCT_ALREADY_ATTACHED_TO_CONTRACT_ERROR,
} from 'src/constants';
import { ContractTermContext } from 'src/contexts/contract-term-context';
import { ContractTermConditionsList } from './contract-term-conditions-list';
import type { AbacusContractAttachmentsAccount } from 'src/types/abacus-account';

export const ProductExceptionForm = () => {
    let labelAttachmentIds: number[] | undefined;
    const { state, dispatch } = useContext(ContractTermContext);

    const { contractId, contractTermId } = useParams<{
        contractId: string;
        contractTermId: string;
    }>();
    const [labelIds, setLabelIds] = useState<number[] | undefined>([]);
    const [accountData, setAccountData] = useState(
        {} as AbacusContractAttachmentsAccount
    );
    const [existingUpcs, setExistingUpcs] = useState<string[]>([]);
    const setErrors = (error: string[]) =>
        dispatch({ type: SET_ERRORS, error });

    // @ts-expect-error: not sure why the contractId gets cast to number, the use hook wants a string
    const { data: contract } = useContractTerms(parseInt(contractId, 10));

    const formChangeHandler: ChangeEventHandler<HTMLInputElement> = e => {
        const {
            target: { value },
        } = e;
        const attachments = value || [];
        dispatch({ type: SET_CONTRACT_TERM_ATTACHMENTS, attachments });
    };

    useEffect(() => {
        if (state.attachments.length > 0 && state.conditions.length === 0)
            dispatch({ type: SET_DEFAULT_CONDITION });
    }, [state.attachments]);

    useEffect(() => {
        if (!isEmpty(contract) && contract.abacusContractTerms) {
            const terms = contract.abacusContractTerms;
            const { account } = terms[0].contract;
            setAccountData(account);

            const labelTerm = terms.filter(
                term => term.termType === CONTRACT_TERM_TYPES.LABEL
            );
            if (isEmpty(labelTerm)) {
                const baseTerm = terms.filter(term => term.isBaseTerm);
                labelAttachmentIds =
                    baseTerm[0]?.attachmentsRelations?.labelIds?.map(
                        attachmentId => parseInt(attachmentId, 10)
                    );
            } else
                labelAttachmentIds = labelTerm?.[0]?.attachments?.map(
                    attachmentId => parseInt(attachmentId, 10)
                );
            setLabelIds(labelAttachmentIds);

            const allProductAttachments: string[] = [...existingUpcs];
            const productTerms = terms.filter(
                term =>
                    term.termType === CONTRACT_TERM_TYPES.PRODUCT &&
                    term.contractTermId !== contractTermId
            );
            productTerms.forEach(productTerm => {
                allProductAttachments.push(...(productTerm.attachments ?? []));
            });
            setExistingUpcs(allProductAttachments);
        }
    }, [contract]);

    useEffect(() => {
        const conflictAttachments = existingUpcs.filter(upc =>
            state.attachments.includes(upc)
        );
        if (!isEmpty(conflictAttachments))
            setErrors([
                `${PRODUCT_ALREADY_ATTACHED_TO_CONTRACT_ERROR} (${conflictAttachments.join(
                    ', '
                )})`,
            ]);
    }, [state.attachments, state.conditions]);

    return (
        <div className="ContractProductExceptionForm-block">
            <h2>Product Exception</h2>
            <Container>
                <Row className="BaseRateHorizontalRow">
                    <Col sm={2}>
                        <Label text="Product(s)" />
                    </Col>
                    <Col sm={5}>
                        <ProductSearchableSelect
                            accountId={accountData ? accountData.accountId : ''}
                            contractTermId={contractTermId}
                            contractId={contractId}
                            onChange={formChangeHandler}
                            productUpcs={state.attachments}
                            labelIds={labelIds}
                            setErrors={setErrors}
                        />
                    </Col>
                </Row>
                {(state.attachments.length > 0 ||
                    state.conditions.length > 0) && (
                    <ContractTermConditionsList />
                )}
            </Container>
        </div>
    );
};

export default ProductExceptionForm;
