import type { JSX } from 'react';
import React, { useContext } from 'react';
import {
    Button,
    Card,
    Table,
    Container,
    Row,
    Col,
} from '@theorchard/suite-components';
import { useFeatureFlag } from '@theorchard/suite-frontend';
import { GlyphIcon } from '@theorchard/suite-icons';
import { capitalize, get, groupBy } from 'lodash-es';
import { Link, useParams } from 'react-router-dom';
import ContractTermLabelName from 'src/components/contract-detail/contract-term-label-name';
import ContractTermProductName from 'src/components/contract-detail/contract-term-product-name';
import ContractTermTrackName from 'src/components/contract-detail/contract-term-track-name';
import ContractTermTracks from 'src/components/contract-detail/contract-term-tracks';
import RestrictedByAbacusProfileWrapper from 'src/components/restricted-by-abacus-profile-wrapper';
import { CONTRACT_TERM_TYPES, USER_FEATURES } from 'src/constants';
import { ContractTermContext } from 'src/contexts/contract-term-context';
import { createNewTerms, updateTerms } from 'src/urls/frontend-royalties';
import { getCountryName } from 'src/utils/country';
import type { GetContractTermQuery } from 'src/apollo/queries/contract-term/__generated__/get-contract-term';
import type {
    ContractTermFormatted,
    ContractTermDetailFormatted,
} from 'src/types/contract-term';

type AbacusContractTerm = NonNullable<
    GetContractTermQuery['abacusContractTerm']
>;
type Conditions = AbacusContractTerm['conditions'] extends (infer T)[] | null
    ? T
    : null;

export interface ContractTermsDetailPropTypes {
    contractTerms: AbacusContractTerm[];
    termType: string;
}

const ContractTermsDetail: React.FC<ContractTermsDetailPropTypes> = ({
    contractTerms,
    termType,
}) => {
    const { contractId } = useParams<{
        contractId: string;
    }>();

    const isFeatureAbacusImproveTrackSearchEnabled = useFeatureFlag(
        USER_FEATURES.ABACUS_IMPROVE_TRACK_SEARCH
    );

    const NO_TERMS_MESSAGE = `No ${capitalize(
        termType
    )} Terms have been defined for this contract.`;

    const fetchContractTermCatalog = (
        contractTerm: AbacusContractTerm
    ): JSX.Element => {
        if (
            contractTerm.termType === CONTRACT_TERM_TYPES.PRODUCT &&
            contractTerm.attachments
        ) {
            return (
                <>
                    {contractTerm.attachments.map((productUpc: string) => (
                        <ContractTermProductName
                            key={productUpc}
                            productUpc={productUpc}
                        />
                    ))}
                </>
            );
        }

        if (contractTerm.termType === CONTRACT_TERM_TYPES.TRACK) {
            if (isFeatureAbacusImproveTrackSearchEnabled)
                return (
                    <ContractTermTracks
                        contractTermId={contractTerm.contractTermId}
                        tracksIsrcs={contractTerm.attachments}
                    />
                );
            return (
                <ContractTermTrackName
                    isrcs={contractTerm?.attachments ?? []}
                />
            );
        }

        return <div>All</div>;
    };

    const formatContractTermConditions = (
        contractTermCondition: Conditions
    ): ContractTermDetailFormatted => {
        const { state } = useContext(ContractTermContext);
        const storeList = state.stores;
        const transactionTypeList = state.transactionTypes;

        const stores = get(contractTermCondition, 'conditions.stores', []);

        let storesString: string;

        if (!stores.length) {
            storesString = 'All';
        } else {
            storesString = stores
                .map((store: string | number) => storeList[store])
                .join(', ');
        }

        const transactionTypes = get(
            contractTermCondition,
            'conditions.transactionTypes',
            []
        );

        let transactionTypesString: string;

        if (!transactionTypes.length) transactionTypesString = 'All';
        else
            transactionTypesString = transactionTypes
                .map(
                    (transactionType: string | number) =>
                        transactionTypeList[transactionType] &&
                        transactionTypeList[transactionType].txnTypeCode.concat(
                            ' - ',
                            transactionTypeList[transactionType].txnTypeName
                        )
                )
                .join(', ');

        const countries = get(
            contractTermCondition,
            'conditions.countries',
            []
        );

        let countriesString: string;

        if (countries.length)
            countriesString = countries
                .map((code: string) => getCountryName(code))
                .join(', ');
        else countriesString = 'All';

        const labelShare = get(contractTermCondition, 'termRate', null);
        return {
            transactionType: transactionTypesString,
            service: storesString,
            country: countriesString,
            labelShare: labelShare,
        };
    };

    const formatContractTermData = (
        unformattedContractTermData: AbacusContractTerm
    ): ContractTermFormatted => {
        const formattedTermId: string =
            unformattedContractTermData.contractTermId;
        const formattedCatalog: JSX.Element = fetchContractTermCatalog(
            unformattedContractTermData
        );

        let formattedLabelIds: string[] | null | undefined = [];
        if (
            unformattedContractTermData.termType === CONTRACT_TERM_TYPES.LABEL
        ) {
            formattedLabelIds = unformattedContractTermData.attachments;
        } else {
            formattedLabelIds =
                unformattedContractTermData.attachmentsRelations?.labelIds;
        }
        const formattedContractTermName: string | null =
            unformattedContractTermData.contractTermName;

        const conditions: Conditions[] | null =
            unformattedContractTermData.conditions;
        const formattedDetails: ContractTermDetailFormatted[] =
            conditions?.map((condition: Conditions) =>
                formatContractTermConditions(condition)
            ) || [];

        const formattedContractTermData: ContractTermFormatted = {
            termId: formattedTermId,
            catalog: formattedCatalog,
            labelIds: formattedLabelIds,
            contractTermName: formattedContractTermName,
            details: formattedDetails,
            actions: 'TODO: Implement by ACC-6912',
        };

        return formattedContractTermData;
    };

    const renderTermBlock = (
        contractTermsUnformattedDataList: AbacusContractTerm[]
    ) => {
        const contractTermsFormattedDataList: ContractTermFormatted[] =
            contractTermsUnformattedDataList?.map(
                (contractTermUnformattedData: AbacusContractTerm) =>
                    formatContractTermData(contractTermUnformattedData)
            ) || [];

        const contractTermsFormattedDataMap = groupBy(
            contractTermsFormattedDataList,
            (contractTermsFormattedData: ContractTermFormatted) =>
                `${contractTermsFormattedData.termId}-${contractTermsFormattedData.catalog}`
        );

        return Object.values(contractTermsFormattedDataMap).map(
            (
                contractTermFormattedDataList: ContractTermFormatted[],
                contractTermFormattedDataMapIndex: number
            ) => {
                const contractTermFormattedDataObject: ContractTermFormatted =
                    contractTermFormattedDataList[0];
                return (
                    <div
                        key={contractTermFormattedDataMapIndex}
                        data-testid={`termBlock${contractTermFormattedDataMapIndex}`}
                    >
                        <div className="ContractTermsConditions-labelInfoBlock">
                            <span
                                className="ContractTermsConditions-contractTermName"
                                data-testid={`termBlockContractTermName${contractTermFormattedDataMapIndex}`}
                            >
                                {
                                    contractTermFormattedDataObject.contractTermName
                                }
                            </span>
                            {contractTermFormattedDataObject.labelIds!.map(
                                (
                                    contractTermLabelId: string,
                                    contractTermLabelIndex: number
                                ) => {
                                    return (
                                        <span
                                            key={contractTermLabelIndex}
                                            className="mb-2 text-muted"
                                            data-testid={`termBlockContractLabelId${contractTermFormattedDataMapIndex}${contractTermLabelIndex}`}
                                        >
                                            &nbsp;&nbsp;
                                            <GlyphIcon name="dot" size={12} />
                                            &nbsp;&nbsp;
                                            <ContractTermLabelName
                                                labelId={contractTermLabelId}
                                            />
                                        </span>
                                    );
                                }
                            )}
                        </div>
                        <Table bordered>
                            <colgroup>
                                <col style={{ width: '5%' }} />
                                <col style={{ width: '22%' }} />
                                <col style={{ width: '20%' }} />
                                <col style={{ width: '20%' }} />
                                <col style={{ width: '20%' }} />
                                <col style={{ width: '8%' }} />
                                <col style={{ width: '5%' }} />
                            </colgroup>
                            <thead>
                                <tr>
                                    <th
                                        className="ContractTermsConditions-tableRowHeader"
                                        data-testid="tableHeaderTermId"
                                    >
                                        term id
                                    </th>
                                    <th
                                        className="ContractTermsConditions-tableRowHeader"
                                        data-testid="tableHeaderCatalog"
                                    >
                                        catalog
                                    </th>
                                    <th
                                        className="ContractTermsConditions-tableRowHeader"
                                        data-testid="tableHeaderTransactionType"
                                    >
                                        transaction type
                                    </th>
                                    <th
                                        className="ContractTermsConditions-tableRowHeader"
                                        data-testid="tableHeaderService"
                                    >
                                        service
                                    </th>
                                    <th
                                        className="ContractTermsConditions-tableRowHeader"
                                        data-testid="tableHeaderCountry"
                                    >
                                        country
                                    </th>
                                    <th
                                        className="ContractTermsConditions-tableRowHeader"
                                        data-testid="tableHeaderLabelShare"
                                    >
                                        label&apos;s share
                                    </th>
                                    <th
                                        className="ContractTermsConditions-tableRowHeader"
                                        data-testid="tableHeaderActions"
                                    >
                                        actions
                                    </th>
                                </tr>
                            </thead>
                            <tbody>
                                {contractTermFormattedDataList.map(
                                    (
                                        contractTermFormattedDataObject: any,
                                        contractTermFormattedDataListIndex: number
                                    ) =>
                                        contractTermFormattedDataObject.details.map(
                                            (
                                                detail: ContractTermDetailFormatted,
                                                detailIndex: number
                                            ) => (
                                                <tr
                                                    key={
                                                        contractTermFormattedDataListIndex +
                                                        '-' +
                                                        detailIndex
                                                    }
                                                >
                                                    {detailIndex === 0 ? (
                                                        <td
                                                            rowSpan={
                                                                contractTermFormattedDataObject
                                                                    .details
                                                                    .length
                                                            }
                                                            data-testid={`termBlockContractTermId${contractTermFormattedDataMapIndex}${detailIndex}`}
                                                        >
                                                            {
                                                                contractTermFormattedDataObject.termId
                                                            }
                                                        </td>
                                                    ) : null}
                                                    {detailIndex === 0 ? (
                                                        <td
                                                            rowSpan={
                                                                contractTermFormattedDataObject
                                                                    .details
                                                                    .length
                                                            }
                                                            data-testid={`termBlockContractCatalog${contractTermFormattedDataMapIndex}${detailIndex}`}
                                                        >
                                                            {
                                                                contractTermFormattedDataObject.catalog
                                                            }
                                                        </td>
                                                    ) : null}
                                                    <td
                                                        data-testid={`termBlockContractTransactionType${contractTermFormattedDataMapIndex}${detailIndex}`}
                                                    >
                                                        {detail.transactionType}
                                                    </td>
                                                    <td
                                                        data-testid={`termBlockContractService${contractTermFormattedDataMapIndex}${detailIndex}`}
                                                    >
                                                        {detail.service}
                                                    </td>
                                                    <td
                                                        data-testid={`termBlockContractCountry${contractTermFormattedDataMapIndex}${detailIndex}`}
                                                    >
                                                        {detail.country}
                                                    </td>
                                                    <td
                                                        data-testid={`termBlockContractLabelShare${contractTermFormattedDataMapIndex}${detailIndex}`}
                                                    >
                                                        {detail.labelShare}%
                                                    </td>
                                                    {detailIndex === 0 ? (
                                                        <td
                                                            rowSpan={
                                                                contractTermFormattedDataObject
                                                                    .details
                                                                    .length
                                                            }
                                                            className="ContractTermsConditions-tableRowEditButtonRow"
                                                        >
                                                            <RestrictedByAbacusProfileWrapper>
                                                                <Link
                                                                    data-testid={`termBlockContractEditLink${contractTermFormattedDataMapIndex}${detailIndex}`}
                                                                    to={updateTerms(
                                                                        contractId,
                                                                        contractTermFormattedDataObject.termId,
                                                                        termType
                                                                    )}
                                                                >
                                                                    <Button
                                                                        variant="quartenary"
                                                                        className="ContractTermsConditions-tableRowEditButton"
                                                                        data-testid={`termBlockContractEditButton${contractTermFormattedDataMapIndex}${detailIndex}`}
                                                                    >
                                                                        Edit
                                                                    </Button>
                                                                </Link>
                                                            </RestrictedByAbacusProfileWrapper>
                                                        </td>
                                                    ) : null}
                                                </tr>
                                            )
                                        )
                                )}
                            </tbody>
                        </Table>
                        <br />
                    </div>
                );
            }
        );
    };

    return (
        <Card data-testid="contractTermConditionsCard">
            <Card.Body className="ContractTermsConditions-customCardBody">
                <Card.Title>
                    <Container fluid>
                        <Row>
                            <Col md={6} className="px-0">
                                <span
                                    className="ContractTermsConditions-customCardTitle"
                                    data-testid="contractTermsContainerTitle"
                                >
                                    <h3>{termType} terms</h3>
                                </span>
                            </Col>
                            <RestrictedByAbacusProfileWrapper>
                                <Col
                                    md={6}
                                    className="ContractTermsConditions-customAddButtonColumn px-0"
                                >
                                    <Link
                                        to={createNewTerms(
                                            contractId,
                                            termType
                                        )}
                                        data-testid={`contractTermsAddPageLink${capitalize(
                                            termType
                                        )}`}
                                    >
                                        <Button
                                            variant="primary"
                                            className="ContractTermsConditions-customAddButton"
                                            data-testid={`contractTermsAddButton${capitalize(
                                                termType
                                            )}`}
                                        >
                                            <span>&nbsp;+ Add&nbsp;</span>
                                        </Button>
                                    </Link>
                                </Col>
                            </RestrictedByAbacusProfileWrapper>
                        </Row>
                    </Container>
                </Card.Title>
                {contractTerms.length > 0 ? (
                    renderTermBlock(contractTerms)
                ) : (
                    <Card.Subtitle
                        className="ContractTermsConditions-customCardSubtitle"
                        data-testid="contractTermsNoTermsMessage"
                    >
                        <span className="mb-2 text-muted">
                            {NO_TERMS_MESSAGE}
                        </span>
                    </Card.Subtitle>
                )}
            </Card.Body>
        </Card>
    );
};

export default ContractTermsDetail;
