import { ApolloClient } from '@apollo/client';
import { getContract } from 'src/apollo/queries/contract';
import {
    BulkEditEntryBase,
    BulkSchema,
    runInBatches,
} from './common-bulk-edit-schema';
import type { GridTableColumnDefinition } from '@theorchard/suite-components';
import React from 'react';
import { Link } from 'react-router-dom';
import { getContractDetail } from 'src/urls/frontend-royalties';
import deleteContractReserve from 'src/apollo/mutations/contract-reserve/delete-contract-reserve.gql';
import {
    DELETE_CONTRACT_RESERVE_MAX_PARALLEL,
    GET_CONTRACT_MAX_PARALLEL,
} from 'src/components/contract-bulk-edit/common/edit-schema/constants';

export const CONTRACT_DELETE_RESERVES_TABLE_HEADERS: GridTableColumnDefinition<ContractDeleteReservesBulkEditEntry>[] =
    [
        {
            name: 'contractId',
            title: 'Contract Id',
        },
        {
            name: 'contractName',
            title: 'Contract Name',
            Cell: ({ data: { contractId, contractName } }: any) => (
                <div>
                    {contractName ? (
                        <Link
                            key={contractId}
                            to={getContractDetail(contractId)}
                        >
                            {contractName}
                        </Link>
                    ) : (
                        '-'
                    )}
                </div>
            ),
        },
        {
            name: 'hasReserve',
            title: 'Has Reserve',
        },
    ];

export interface ContractDeleteReservesBulkEditEntry extends BulkEditEntryBase {
    id: string;
    contractId: string;
    contractName: string | undefined | null;
    contractReserveId: string | undefined | null;
    hasReserve: boolean;
}

export const contractDeleteReservesSchema: BulkSchema<ContractDeleteReservesBulkEditEntry> =
    {
        id: 'contractDeleteReserves',
        displayName: 'Contract Delete Reserves',
        columns: CONTRACT_DELETE_RESERVES_TABLE_HEADERS,
        expectedFileColumns: [
            {
                name: 'contract_id_delete_reserves',
                description: 'Contract ID whose reserves should be deleted',
            },
        ],
        async toEntries(apolloClient: ApolloClient<object>, rows: any[]) {
            const mapEntry = async (
                entry: any
            ): Promise<ContractDeleteReservesBulkEditEntry> => {
                const contractId: string = entry['contract_id_delete_reserves'];

                const { data: contractData } = await apolloClient.query({
                    query: getContract,
                    variables: {
                        contractId,
                        groupAdmin: 'PRESENTATIONAL',
                    },
                    fetchPolicy: 'network-only',
                });

                if (!contractData.abacusContract) {
                    return {
                        id: contractId,
                        contractId,
                        contractName: undefined,
                        contractReserveId: undefined,
                        hasReserve: false,
                    };
                }

                return {
                    id: contractId,
                    contractId,
                    contractName: contractData.abacusContract.contractName,
                    contractReserveId:
                        contractData.abacusContract.reserve?.contractReserveId,
                    hasReserve: !!contractData.abacusContract.reserve,
                };
            };

            return await runInBatches(
                rows,
                GET_CONTRACT_MAX_PARALLEL,
                mapEntry
            );
        },
        async apply(apolloClient, entries, onSuccess, onFail) {
            await runInBatches(
                entries,
                DELETE_CONTRACT_RESERVE_MAX_PARALLEL,
                async entry => {
                    if (!entry.contractName) {
                        onFail(
                            entry,
                            new Error('No contract found.'),
                            'No contract found.'
                        );
                        return;
                    }

                    if (!entry.hasReserve) {
                        onFail(
                            entry,
                            new Error('No reserve to delete.'),
                            'No reserve to delete.'
                        );
                        return;
                    }

                    try {
                        await apolloClient.mutate({
                            mutation: deleteContractReserve,
                            variables: {
                                contractId: entry.contractId,
                            },
                        });
                        onSuccess(entry);
                    } catch (error) {
                        onFail(
                            entry,
                            error,
                            'Error deleting contract reserves.'
                        );
                    }
                }
            );
        },
    };
