import { ApolloClient } from '@apollo/client';
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 { getAccountDetail } from 'src/urls/frontend-royalties';
import getAccountFullDetail from 'src/apollo/queries/account/get-account-full-detail.gql';
import updateAccountPaymentTerm from 'src/apollo/mutations/account-payment-term/update-account-payment-term.gql';
import {
    GET_ACCOUNT_DETAIL_MAX_PARALLEL,
    UPDATE_ACCOUNT_CURRENCY_MAX_PARALLEL,
} from 'src/components/contract-bulk-edit/common/edit-schema/constants';

const ACCOUNT_CURRENCY_TABLE_HEADERS: GridTableColumnDefinition<AccountCurrencyBulkEditEntry>[] =
    [
        {
            name: 'accountName',
            title: 'Account Name',
            Cell: ({ data: { accountId, accountName } }: any) => (
                <div>
                    {accountName ? (
                        <Link key={accountId} to={getAccountDetail(accountId)}>
                            {accountName}
                        </Link>
                    ) : (
                        '-'
                    )}
                </div>
            ),
        },
        {
            name: 'currentCurrency',
            title: 'Current Currency',
        },
        {
            name: 'currencyToSet',
            title: 'Currency To Set',
        },
    ];

export interface AccountCurrencyBulkEditEntry extends BulkEditEntryBase {
    id: string;
    accountId: string;
    accountName: string | undefined | null;
    accountPaymentTermId: string | undefined | null;
    currentCurrency: string | undefined | null;
    currencyToSet: string;
}

export const accountCurrencySchema: BulkSchema<AccountCurrencyBulkEditEntry> = {
    id: 'accountCurrency',
    displayName: 'Account Currency',
    columns: ACCOUNT_CURRENCY_TABLE_HEADERS,
    expectedFileColumns: [
        {
            name: 'account_id',
            description: 'Account ID to update',
        },
        {
            name: 'currency_code',
            description: 'Currency code to set',
        },
    ],
    async toEntries(apolloClient: ApolloClient<object>, rows: any[]) {
        const mapEntry = async (
            entry: any
        ): Promise<AccountCurrencyBulkEditEntry> => {
            const accountId: string = entry['account_id'];
            const currencyToSet: string = entry['currency_code'];

            const { data } = await apolloClient.query({
                query: getAccountFullDetail,
                variables: { accountId },
                fetchPolicy: 'network-only',
            });

            if (!data.abacusAccount) {
                return {
                    id: accountId,
                    accountId,
                    accountName: undefined,
                    accountPaymentTermId: undefined,
                    currentCurrency: undefined,
                    currencyToSet,
                };
            }

            return {
                id: accountId,
                accountId,
                accountName: data.abacusAccount.accountName,
                accountPaymentTermId:
                    data.abacusAccount.accountPaymentTerm?.accountPaymentTermId,
                currentCurrency:
                    data.abacusAccount.accountPaymentTerm?.currencyCode,
                currencyToSet,
            };
        };

        return await runInBatches(
            rows,
            GET_ACCOUNT_DETAIL_MAX_PARALLEL,
            mapEntry
        );
    },
    async apply(apolloClient, entries, onSuccess, onFail) {
        await runInBatches(
            entries,
            UPDATE_ACCOUNT_CURRENCY_MAX_PARALLEL,
            async entry => {
                if (!entry.accountName) {
                    onFail(
                        entry,
                        new Error('No account to update.'),
                        'No account to update.'
                    );
                    return;
                }

                if (!entry.accountPaymentTermId) {
                    onFail(
                        entry,
                        new Error('No account payment term found.'),
                        'No account payment term found.'
                    );
                    return;
                }

                try {
                    await apolloClient.mutate({
                        mutation: updateAccountPaymentTerm,
                        variables: {
                            accountPaymentTermId: entry.accountPaymentTermId,
                            currencyCode: entry.currencyToSet,
                        },
                    });
                    onSuccess(entry);
                } catch (error) {
                    onFail(entry, error, 'Error updating account currency.');
                }
            }
        );
    },
};
