import type { FC } from 'react';
import React, { useState, useMemo } from 'react';
import { Modal, GridTable, Tag, Button } from '@theorchard/suite-components';
import { GlyphIcon } from '@theorchard/suite-icons';
import { values } from 'lodash-es';
import {
    VAT_DOCS_FAILURE_REASON,
    VAT_DOCS_FAILURE_REASON_MESSAGES,
} from 'src/constants';
import { exportCsv } from 'src/utils/export-csv';
import type { GetVatInvoicesQuery } from 'src/apollo/queries/statement-periods/__generated__/get-vat-invoices';

type StatementInvoices = NonNullable<
    GetVatInvoicesQuery['moneyhubStatementInvoices']
>[0];

const CLASS_NAME = 'FailedVatDocsModal';

export const TEST_ID_FAILED_DOCS_MODAL = 'failed-vat-docs-modal';

const DEFAULT_PAGE_SIZE = 10;

const TERM_FAILED_DOCS_MODAL_TITLE = 'Failed VAT Documents';
export const TERM_RETRY_BUTTON = 'Retry to generate';
const TERM_STATEMENT_PERIOD = 'Statement Period';
const TERM_PAID_BY = 'Paid By';
const TERM_ACCOUNT = 'Account';
const TERM_ACCOUNT_NAME = 'Account Name';
const TERM_ACCOUNT_ID = 'Account Id';
const TERM_NUMBER_OF_DOCS = '# of failed documents';
const TERM_FAILURE_REASON = 'Failure reason';

interface Props {
    toggleModal: () => void;
    isOpen: boolean;
    failedDocs: StatementInvoices[];
    statementPeriodName: string;
    paymentEntityName: string;
    onRetryVatDocs: () => void;
}

interface ReduceReturnType {
    [key: string]: Partial<StatementInvoices> & { numOfDocs?: number };
}

export const FailedVatDocsModal: FC<Props> = ({
    isOpen,
    toggleModal,
    failedDocs,
    statementPeriodName,
    paymentEntityName,
    onRetryVatDocs,
}) => {
    const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE);
    const [page, setPage] = useState(0);

    const failedDocsByAccount = useMemo(
        () =>
            failedDocs.reduce<ReduceReturnType>((acc, doc) => {
                const aggregationKey: string =
                    doc.accountId + doc.failureReason;

                acc[aggregationKey] = {
                    ...doc,
                    numOfDocs: (acc[aggregationKey]?.numOfDocs ?? 0) + 1,
                };

                return acc;
            }, {}),
        [failedDocs]
    );

    const failedDocsByAccountList = values(failedDocsByAccount);
    const failedDocsByAccountCount = failedDocsByAccountList.length;

    const failedDocsByAccountListPaginated = failedDocsByAccountList.slice(
        page * pageSize,
        (page + 1) * pageSize
    );

    const renderTitle = () => (
        <div className={`${CLASS_NAME}-title`}>
            <span>{TERM_FAILED_DOCS_MODAL_TITLE}</span>
            <Tag
                text={failedDocs.length.toString()}
                className={`${CLASS_NAME}-count-tag`}
                testId={`${TEST_ID_FAILED_DOCS_MODAL}-count-tag`}
            />
        </div>
    );

    const renderDetails = () => (
        <div className={`${CLASS_NAME}-details`}>
            <div className={`${CLASS_NAME}-details-items`}>
                <div className={`${CLASS_NAME}-details-item`}>
                    <span className={`${CLASS_NAME}-details-item-label`}>
                        {TERM_STATEMENT_PERIOD}
                    </span>
                    <span className={`${CLASS_NAME}-details-item-value`}>
                        {statementPeriodName}
                    </span>
                </div>
                <div className={`${CLASS_NAME}-details-item`}>
                    <span className={`${CLASS_NAME}-details-item-label`}>
                        {TERM_PAID_BY}
                    </span>
                    <span className={`${CLASS_NAME}-details-item-value`}>
                        {paymentEntityName}
                    </span>
                </div>
            </div>
            <Button
                className={`${CLASS_NAME}-retry-btn`}
                variant="primary"
                onClick={onRetryVatDocs}
            >
                {TERM_RETRY_BUTTON}
            </Button>
        </div>
    );

    const onExport = () => {
        const csvRows = failedDocsByAccountList?.map(doc => ({
            [TERM_ACCOUNT_NAME]: doc.accountName,
            [TERM_ACCOUNT_ID]: doc.accountId,
            [TERM_NUMBER_OF_DOCS]: doc.numOfDocs?.toString(),
            [TERM_FAILURE_REASON]:
                doc.failureReason &&
                VAT_DOCS_FAILURE_REASON_MESSAGES[doc.failureReason],
        }));

        const filename = `Failed_VAT_docs_${paymentEntityName}_${statementPeriodName}`;

        exportCsv(csvRows, filename);
    };

    const renderDocsTable = () => (
        <GridTable
            data={failedDocsByAccountListPaginated}
            className={`${CLASS_NAME}-table`}
            paginated
            totalCount={failedDocsByAccountCount}
            page={page}
            onPageChange={setPage}
            pageSize={pageSize}
            onPageSizeChange={setPageSize}
            exportable
            onExport={onExport}
            rowKey={({ accountId, failureReason }) =>
                `${accountId} + ${failureReason}`
            }
            bordered
            columnDefs={[
                {
                    name: 'account',
                    title: TERM_ACCOUNT,
                    Cell: ({ data: { accountId, accountName } }) => (
                        <span className={`${CLASS_NAME}-account-cell`}>
                            <span>{accountName}</span>
                            <span className={`${CLASS_NAME}-account-cell-id`}>
                                {accountId}
                            </span>
                        </span>
                    ),
                },
                {
                    name: 'numOfDocs',
                    title: TERM_NUMBER_OF_DOCS,
                    align: 'left',
                    maxWidth: '80px',
                    template: 'number',
                },
                {
                    name: 'failureReason',
                    title: TERM_FAILURE_REASON,
                    Cell: ({ data: { failureReason } }) => {
                        if (!failureReason) return null;

                        return (
                            <span className={`${CLASS_NAME}-failure-cell`}>
                                {failureReason ===
                                    VAT_DOCS_FAILURE_REASON.SYSTEM_ERROR && (
                                    <GlyphIcon name="warning" size={16} />
                                )}
                                {
                                    VAT_DOCS_FAILURE_REASON_MESSAGES[
                                        failureReason
                                    ]
                                }
                            </span>
                        );
                    },
                },
            ]}
        />
    );

    return (
        <Modal
            isOpen={isOpen}
            onRequestClose={toggleModal}
            title={renderTitle()}
            className={CLASS_NAME}
            testId={TEST_ID_FAILED_DOCS_MODAL}
        >
            {renderDetails()}
            {renderDocsTable()}
        </Modal>
    );
};
