import React from 'react';
import type { GridTableColumnDefinition } from '@theorchard/suite-components';
import { Form, Select, Tag } from '@theorchard/suite-components';
import { GlyphIcon } from '@theorchard/suite-icons';
import {
    AbacusEarningsTransferTypes,
    AbacusEarningsTransferRateTypes as RateTypesType,
    AbacusEarningsTransferSources as SourcesType,
} from 'src/apollo/definitions/globalTypes';
import {
    AbacusEarningsTransferRateTypes,
    AbacusEarningsTransferSources,
} from 'src/apollo/definitions/globalTypes';
import {
    EARNINGS_TRANSFER_RATE_TYPE_LABELS,
    EARNINGS_TRANSFER_SOURCES_LABELS,
} from 'src/apollo/type-constants/contract-earnings-transfer';
import AccountSelect from 'src/components/contract-list/account-select';
import type { GetContractByIdQuery } from 'src/apollo/queries/contract/__generated__/get-contract-by-id';
import type { TransferRow } from 'src/types/abacus-contract-earnings-transfer';

interface SelectOption<T extends string> {
    label: string;
    value: T;
    disabled?: boolean;
}

export interface RowUiState {
    selectedAccount: { label: string; value: string } | undefined;
    selectedContract: SelectOption<string> | undefined;
    amountError: string | undefined;
    contractOptions: SelectOption<string>[];
    contractsLoading: boolean;
}

export type TransferTableRow = TransferRow & {
    transferType: AbacusEarningsTransferTypes | undefined;
    rowIndex: number;
    uiState: RowUiState;
};

const RATE_TYPE_OPTIONS: SelectOption<RateTypesType>[] = Object.values(
    AbacusEarningsTransferRateTypes
).map(value => ({ label: EARNINGS_TRANSFER_RATE_TYPE_LABELS[value], value }));

const SOURCE_OPTIONS: SelectOption<SourcesType>[] = Object.values(
    AbacusEarningsTransferSources
).map(value => ({ label: EARNINGS_TRANSFER_SOURCES_LABELS[value], value }));

export const createEmptyUiState = (): RowUiState => ({
    selectedAccount: undefined,
    selectedContract: undefined,
    amountError: undefined,
    contractOptions: [],
    contractsLoading: false,
});

export const createUiState = (row: TransferRow): RowUiState => ({
    selectedAccount: {
        label: row.toAccountName || '',
        value: row.toAccountId || '',
    },
    selectedContract: {
        label: row.toContractName || '',
        value: row.toContractId || '',
    },
    amountError: undefined,
    contractOptions: [],
    contractsLoading: false,
});

export const validateAmount = (
    value: string,
    rateType: RateTypesType | undefined
): string | undefined => {
    if (value === '') return undefined;
    const amount = parseFloat(value);
    if (isNaN(amount)) return 'Please enter a valid number';
    if (rateType === AbacusEarningsTransferRateTypes.PERCENT) {
        if (amount <= 0 || amount > 100)
            return 'Value must be between .01 and 100';
    } else if (rateType === AbacusEarningsTransferRateTypes.FLAT_RATE) {
        if (amount <= 0) return 'Value must be a positive number';
    }
    return undefined;
};

type FromContract =
    | NonNullable<GetContractByIdQuery['abacusContract']>
    | null
    | undefined;

interface GetColumnDefsParams {
    fromContract: FromContract;
    onRowChange: (index: number, updated: Partial<TransferRow>) => void;
    handleAccountChange: (
        index: number,
        accountId: string | undefined,
        account: { label: string; value: string } | undefined
    ) => void;
    updateRowUiState: (index: number, updated: Partial<RowUiState>) => void;
}

export const getEarningsTransferDeleteColumnDef = (
    onDeleteRow: (index: number) => void
): GridTableColumnDefinition<TransferTableRow> => ({
    name: 'actions',
    title: 'Actions',
    minWidth: '60px',
    Cell: ({ data }: { data: TransferTableRow }) => (
        <button
            type="button"
            className="ContractEarningsTransferConfigScreen-deleteButton"
            onClick={() => onDeleteRow(data.rowIndex)}
            data-testid={`earningsTransferDeleteRow-${data.rowIndex}`}
        >
            <GlyphIcon name="trash" size={16} />
        </button>
    ),
});

export const getEarningsTransferBaseColumnDefs = ({
    fromContract,
    onRowChange,
    handleAccountChange,
    updateRowUiState,
}: GetColumnDefsParams): GridTableColumnDefinition<TransferTableRow>[] => [
    {
        name: 'fromContract',
        title: 'From Contract',
        minWidth: '160px',
        Cell: ({ data }) => {
            const fromContractOption: SelectOption<string> | undefined =
                fromContract
                    ? {
                          label: fromContract.contractName,
                          value: fromContract.contractId,
                      }
                    : undefined;
            return (
                <div className="d-flex flex-column ContractEarningsTransferConfigScreen-fromContract">
                    <Select<SelectOption<string>>
                        name={`fromContract-${data.rowIndex}`}
                        options={fromContractOption ? [fromContractOption] : []}
                        testId={`earningsTransferFromContract-${data.rowIndex}`}
                        selectedValue={fromContractOption}
                        disabled
                    />
                    <div className="d-flex flex-row align-items-center suite-text-small ContractEarningsTransfer-AccountName">
                        Account: {fromContract?.account?.accountName ?? ''}
                    </div>
                    <div className="d-flex flex-row">
                        <Tag text="Current Contract" />
                    </div>
                </div>
            );
        },
    },
    {
        name: 'toAccount',
        title: 'To Account',
        minWidth: '200px',
        Cell: ({ data }) => (
            <div className={'ContractEarningsTransferConfigScreen-toAccount'}>
                <AccountSelect
                    selectedAccount={data.uiState.selectedAccount}
                    setSelectedAccount={(
                        account: { label: string; value: string } | undefined
                    ) =>
                        updateRowUiState(data.rowIndex, {
                            selectedAccount: account,
                        })
                    }
                    changeHandler={(params: object) => {
                        const { target } = params as {
                            target: {
                                name: string;
                                value: number[] | null;
                            };
                        };
                        const accountId =
                            target.value?.[0]?.toString() ?? undefined;
                        const account = accountId
                            ? data.uiState.selectedAccount
                            : undefined;
                        handleAccountChange(data.rowIndex, accountId, account);
                    }}
                />
            </div>
        ),
    },
    {
        name: 'toContract',
        title: 'To Contract',
        minWidth: '160px',
        Cell: ({ data }) => (
            <div className="d-flex flex-column ContractEarningsTransferConfigScreen-toContract">
                <Select
                    name={`toContract-${data.rowIndex}`}
                    placeholder={
                        data.uiState.contractsLoading
                            ? 'Loading...'
                            : 'Select Contract'
                    }
                    options={data.uiState.contractOptions}
                    testId={`earningsTransferToContract-${data.rowIndex}`}
                    selectedValue={data.uiState.selectedContract}
                    disabled={
                        !data.toAccountId || data.uiState.contractsLoading
                    }
                    onChange={(option: SelectOption<string> | undefined) => {
                        updateRowUiState(data.rowIndex, {
                            selectedContract: option,
                        });
                        onRowChange(data.rowIndex, {
                            toContractId: option?.value ?? undefined,
                        });
                    }}
                />
                <div className="suite-text-small ContractEarningsTransfer-AccountName">
                    Account: {data.uiState.selectedAccount?.label ?? ''}
                </div>
            </div>
        ),
    },
    {
        name: 'rateType',
        title: 'Rate Type',
        minWidth: '140px',
        Cell: ({ data }) => (
            <Select
                name={`rateType-${data.rowIndex}`}
                placeholder="Select Rate"
                options={RATE_TYPE_OPTIONS}
                testId={`earningsTransferRateType-${data.rowIndex}`}
                portalElement={document.body}
                selectedValue={
                    RATE_TYPE_OPTIONS.find(o => o.value === data.rateType) ??
                    undefined
                }
                disabled={
                    data.transferType === AbacusEarningsTransferTypes.RECLASS
                }
                onChange={(option: SelectOption<RateTypesType> | undefined) =>
                    onRowChange(data.rowIndex, {
                        rateType: option?.value ?? undefined,
                        input: undefined,
                    })
                }
            />
        ),
    },
    {
        name: 'amount',
        title: 'Amount',
        minWidth: '120px',
        Cell: ({ data }) => {
            const [localValue, setLocalValue] = React.useState(
                data.transferAmount ?? ''
            );

            return (
                <div className="d-flex flex-column">
                    <Form.Control
                        type="text"
                        name={`transferAmount-${data.rowIndex}`}
                        isInvalid={!!data.uiState.amountError}
                        placeholder="Input value"
                        value={localValue}
                        disabled={
                            data.transferType ===
                            AbacusEarningsTransferTypes.RECLASS
                        }
                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                            setLocalValue(e.target.value);
                            if (data.uiState.amountError) {
                                updateRowUiState(data.rowIndex, {
                                    amountError: validateAmount(
                                        e.target.value,
                                        data.rateType
                                    ),
                                });
                            }
                        }}
                        onBlur={(e: React.FocusEvent<HTMLInputElement>) => {
                            onRowChange(data.rowIndex, {
                                transferAmount: e.target.value,
                            });
                            updateRowUiState(data.rowIndex, {
                                amountError: validateAmount(
                                    e.target.value,
                                    data.rateType
                                ),
                            });
                        }}
                        data-testid={`earningsTransferAmount-${data.rowIndex}`}
                    />
                    {data.uiState.amountError && (
                        <Form.Text className="text-danger">
                            {data.uiState.amountError}
                        </Form.Text>
                    )}
                </div>
            );
        },
    },
    {
        name: 'source',
        title: 'Transfer Source',
        minWidth: '150px',
        Cell: ({ data }) => (
            <Select
                name={`source-${data.rowIndex}`}
                placeholder="Select Source"
                options={
                    data.rateType === AbacusEarningsTransferRateTypes.FLAT_RATE
                        ? SOURCE_OPTIONS.filter(
                              o =>
                                  o.value ===
                                  AbacusEarningsTransferSources.CLOSING_BALANCE
                          )
                        : SOURCE_OPTIONS
                }
                testId={`earningsTransferSource-${data.rowIndex}`}
                portalElement={document.body}
                selectedValue={
                    SOURCE_OPTIONS.find(o => o.value === data.input) ??
                    undefined
                }
                disabled={
                    data.transferType === AbacusEarningsTransferTypes.RECLASS
                }
                onChange={(option: SelectOption<SourcesType> | undefined) =>
                    onRowChange(data.rowIndex, {
                        input: option?.value ?? undefined,
                    })
                }
            />
        ),
    },
    {
        name: 'negative',
        title: 'Process Negative Closing Balances',
        minWidth: '120px',
        Cell: ({ data }) => (
            <div className="d-flex flex-column">
                <Form.Check
                    type="radio"
                    id={`negative-no-${data.rowIndex}`}
                    label="No"
                    checked={!data.negative}
                    onChange={() =>
                        onRowChange(data.rowIndex, { negative: false })
                    }
                    data-testid={`earningsTransferNegativeNo-${data.rowIndex}`}
                />
                <Form.Check
                    type="radio"
                    id={`negative-yes-${data.rowIndex}`}
                    label="Yes"
                    checked={data.negative}
                    onChange={() =>
                        onRowChange(data.rowIndex, { negative: true })
                    }
                    data-testid={`earningsTransferNegativeYes-${data.rowIndex}`}
                />
            </div>
        ),
    },
    {
        name: 'status',
        title: 'Transfer Status',
        minWidth: '120px',
        Cell: ({ data }) => (
            <div className="d-flex flex-column">
                <Form.Check
                    type="radio"
                    id={`status-active-${data.rowIndex}`}
                    label="Active"
                    checked={data.active === true}
                    onChange={() =>
                        onRowChange(data.rowIndex, { active: true })
                    }
                    data-testid={`earningsTransferStatusActive-${data.rowIndex}`}
                />
                <Form.Check
                    type="radio"
                    id={`status-inactive-${data.rowIndex}`}
                    label="Not Active"
                    checked={data.active === false}
                    onChange={() =>
                        onRowChange(data.rowIndex, { active: false })
                    }
                    data-testid={`earningsTransferStatusInactive-${data.rowIndex}`}
                />
            </div>
        ),
    },
];
