import React, { useEffect, useState } from 'react';
import {
    POSITIVE_AMOUNT_REGEX,
    SIGNED_AMOUNT_REGEX,
    POSITIVE_PERCENT_REGEX,
} from '@theorchard/accounting-apps-shared';
import {
    Field,
    Form,
    SegmentedInput,
    Select,
    SkeletonLoader,
} from '@theorchard/suite-components';
import cx from 'classnames';
import { useAccountDetailsForPayment } from 'src/apollo/queries/account';
import { useStatementPeriodCurrentPeriod } from 'src/apollo/queries/statement-periods';
import CurrencySelect from 'src/components/shared/currency-select';
import StatementPeriodDropdown from 'src/components/shared/statement-period-dropdown';
import { INELIGIBLE_ACCOUNT_ALERT_TEXT } from 'src/constants';
import { type ChangeHandlerArgs } from 'src/types/change-handler';
import { statesArePaymentReady } from 'src/utils/action-states';
import AccountSearchDropdown from '../components/accounts-search-dropdown';
import type { ApolloError } from '@apollo/client';
import type {
    Value,
    SingleSelectValue,
} from 'src/components/payment-group-form/components/accounts-search-dropdown/accounts-search-dropdown';
import type { PaymentGroupFormData } from 'src/types/payment-group-form';

const CLASS_NAME = 'CustomPayment';
const TEST_ID = CLASS_NAME;

type FieldsValidationErrors = { [key: string]: string };

export interface PaymentSpecificPaymentProps {
    changeHandler: (params: ChangeHandlerArgs) => void;
    formData: PaymentGroupFormData;
    fieldsValidationErrors?: FieldsValidationErrors;
}

interface PaymentSpecificPaymentDetailsProps extends PaymentSpecificPaymentProps {
    accountId: string;
    onError?: (error: any) => void;
    onLoading?: (loading: boolean) => void;
}

const getValue = (value?: SingleSelectValue): string | undefined => {
    if (!value) return '';

    if (typeof value === 'string') return value;

    return value?.value;
};

const getErrorMessage = (
    field: string,
    fieldsValidationErrors?: FieldsValidationErrors
) => {
    return fieldsValidationErrors?.[field]
        ? { text: fieldsValidationErrors[field], type: 'error' as const }
        : undefined;
};

const CustomPaymentDetails: React.FC<PaymentSpecificPaymentDetailsProps> = ({
    accountId,
    changeHandler,
    formData,
    onError,
    onLoading,
    fieldsValidationErrors,
}) => {
    const {
        amount = '',
        withholdingTaxAmount = '',
        withholdingTaxRate = '',
        vatAmount = '',
        vatRate = '',
        activityStatementPeriodId = '',
        paymentName = '',
    } = formData;

    const {
        data: accountData,
        loading: accountDataLoading,
        error: accountDataError,
    } = useAccountDetailsForPayment(accountId);
    const {
        data: currentStatementPeriod,
        loading: currentStatementPeriodLoading,
        error: currentStatementPeriodError,
    } = useStatementPeriodCurrentPeriod();

    const isLoading = accountDataLoading || currentStatementPeriodLoading;

    const actionStates = accountData?.abacusAccount?.accountPayee?.actionStates;
    const arePaymentReady = statesArePaymentReady(actionStates);
    const isAccountIneligible = arePaymentReady === false;

    const statementPeriodId =
        currentStatementPeriod?.abacusCurrentStatementPeriod?.statementPeriodId;

    useEffect(() => {
        if (formData.statementPeriodId !== statementPeriodId) {
            changeHandler({
                target: {
                    name: 'statementPeriodId',
                    value: statementPeriodId ?? '',
                },
            });
        }
    }, [statementPeriodId]);

    useEffect(() => {
        const error =
            accountDataError ||
            currentStatementPeriodError ||
            (isAccountIneligible ? INELIGIBLE_ACCOUNT_ALERT_TEXT : null);
        onError?.(error);
    }, [
        accountDataError,
        onError,
        isAccountIneligible,
        currentStatementPeriodError,
    ]);

    useEffect(() => {
        onLoading?.(isLoading);
    }, [isLoading, onLoading]);

    const handleAccountContractsChange = (value?: SingleSelectValue) => {
        changeHandler({
            target: { name: 'contractId', value: getValue(value) ?? '' },
        });
    };

    const handleCurrencyChange = (value?: SingleSelectValue) => {
        changeHandler({
            target: { name: 'currency', value: getValue(value) ?? '' },
        });
    };

    const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const { name, value } = e.target;
        changeHandler({ target: { name, value } });
    };

    const handleAmountChange = (
        e: React.ChangeEvent<any>,
        allowNegative = true
    ) => {
        const { name, value } = e.target;
        const regex = allowNegative
            ? SIGNED_AMOUNT_REGEX
            : POSITIVE_AMOUNT_REGEX;

        if (regex.test(value)) {
            changeHandler({ target: { name, value: value.replace(',', '.') } });
        }
    };

    const handleRateChange = (e: React.ChangeEvent<any>) => {
        const { name, value } = e.target;

        if (POSITIVE_PERCENT_REGEX.test(value)) {
            changeHandler({ target: { name, value: value.replace(',', '.') } });
        }
    };

    const handleActivityStatementPeriodChange = (value: SingleSelectValue) => {
        changeHandler({
            target: {
                name: 'activityStatementPeriodId',
                value: getValue(value) ?? '',
            },
        });
    };

    const accountCurrency =
        accountData?.abacusAccount?.accountPaymentTerm?.currencyCode || '';
    const accountContracts = accountData?.abacusAccount?.contracts || [];
    const accountContractOptions = accountContracts.map(contract => ({
        label: `${contract.contractName} - ${contract.contractId}`,
        value: contract.contractId,
    }));

    useEffect(() => {
        if (formData.currency !== accountCurrency)
            handleCurrencyChange(accountCurrency);
    }, [accountCurrency]);

    if (
        accountDataError ||
        isAccountIneligible ||
        currentStatementPeriodError
    ) {
        return null;
    }

    const withLoader = (component: React.ReactNode) =>
        isLoading ? <SkeletonLoader height={40} /> : component;

    return (
        <>
            <Field
                labelText="Currency"
                controlId="currency"
                helpText="Currency is driven by Account Preference"
            >
                {withLoader(
                    <CurrencySelect
                        id="currency"
                        name="currency"
                        value={accountCurrency}
                        onChange={handleCurrencyChange}
                        placeholder="Currency"
                        isDisabled
                    />
                )}
            </Field>
            <Field labelText="Contract" controlId="contractId">
                {withLoader(
                    <Select
                        testId="contractSelect"
                        onChange={handleAccountContractsChange}
                        options={accountContractOptions}
                    />
                )}
            </Field>
            <Field
                labelText="Amount"
                controlId="amount"
                note="Up to 2 decimal places"
            >
                {withLoader(
                    <Form.Control
                        name="amount"
                        value={amount}
                        onChange={e => handleAmountChange(e, false)}
                        placeholder="Enter any amount greater than 0"
                    />
                )}
            </Field>
            <Field
                labelText="WHT"
                controlId="withholdingTaxAmount"
                note="Up to 2 decimal places"
                message={getErrorMessage(
                    'withholdingTaxAmount',
                    fieldsValidationErrors
                )}
            >
                {withLoader(
                    <Form.Control
                        name="withholdingTaxAmount"
                        value={withholdingTaxAmount}
                        onChange={handleAmountChange}
                        placeholder="Enter any amount (this usually is negative)"
                    />
                )}
            </Field>
            <Field
                labelText="WHT Rate"
                controlId="withholdingTaxRate"
                note="Up to 2 decimal places"
                message={getErrorMessage(
                    'withholdingTaxRate',
                    fieldsValidationErrors
                )}
            >
                {withLoader(
                    <SegmentedInput testId="withholdingTaxRate-segmentedInput">
                        <Form.Control
                            name="withholdingTaxRate"
                            value={withholdingTaxRate}
                            onChange={handleRateChange}
                            placeholder="Enter any non-negative rate"
                        />
                        <SegmentedInput.Static>%</SegmentedInput.Static>
                    </SegmentedInput>
                )}
            </Field>
            <Field
                labelText="VAT"
                controlId="vatAmount"
                note="Up to 2 decimal places"
                message={getErrorMessage('vatAmount', fieldsValidationErrors)}
            >
                {withLoader(
                    <Form.Control
                        name="vatAmount"
                        value={vatAmount}
                        onChange={handleAmountChange}
                        placeholder="Enter any amount (this usually is positive)"
                    />
                )}
            </Field>
            <Field
                labelText="VAT Rate"
                controlId="vatRate"
                note="Up to 2 decimal places"
                message={getErrorMessage('vatRate', fieldsValidationErrors)}
            >
                {withLoader(
                    <SegmentedInput testId="vatRate-segmentedInput">
                        <Form.Control
                            name="vatRate"
                            value={vatRate}
                            onChange={handleRateChange}
                            placeholder="Enter any non-negative rate"
                        />
                        <SegmentedInput.Static>%</SegmentedInput.Static>
                    </SegmentedInput>
                )}
            </Field>
            <Field
                labelText="Activity Statement Period"
                controlId="activityStatementPeriodId"
            >
                {withLoader(
                    <StatementPeriodDropdown
                        placeholder="Select Statement Period"
                        value={getValue(activityStatementPeriodId) || ''}
                        onChange={handleActivityStatementPeriodChange}
                        testId={'activityStatementPeriodDropdown'}
                    />
                )}
            </Field>
            <Field labelText="Payment Name" controlId="paymentName">
                {withLoader(
                    <Form.Control
                        name="paymentName"
                        value={paymentName}
                        onChange={handleInputChange}
                        placeholder="Enter Payment Name"
                    />
                )}
            </Field>
        </>
    );
};

const CustomPayment: React.FC<PaymentSpecificPaymentProps> = ({
    changeHandler,
    formData,
    fieldsValidationErrors,
}) => {
    const [error, setError] = useState<Error | ApolloError | string | null>(
        null
    );
    const [isLoading, setIsLoading] = useState(false);
    const { accountOption } = formData;
    const accountId =
        typeof accountOption === 'string'
            ? accountOption
            : accountOption?.value;
    const accountErrorMessage =
        error && (typeof error === 'string' ? error : error.message);

    useEffect(() => {
        if (!accountId) {
            setIsLoading(false);
            setError(null);
            return;
        }
    }, [accountId]);

    const handleAccountChange = (value?: Value) => {
        changeHandler({
            target: { name: 'accountOption', value: value as string },
        });
    };

    return (
        <div
            className={cx(CLASS_NAME, 'PaymentGroupFormFieldsGroup')}
            data-testid={TEST_ID}
        >
            <Field
                labelText="Select Account"
                controlId="accountSearchDropdown"
                message={
                    accountErrorMessage
                        ? {
                              text: accountErrorMessage,
                              type: 'error',
                          }
                        : undefined
                }
            >
                <AccountSearchDropdown
                    onChange={handleAccountChange}
                    disabled={isLoading}
                    selectedValue={accountOption}
                    isMultiSelect={false}
                    id="accountSearchDropdown"
                    testId="accountSearchDropdown"
                />
            </Field>
            {accountId && (
                <CustomPaymentDetails
                    accountId={accountId}
                    changeHandler={changeHandler}
                    onError={setError}
                    onLoading={setIsLoading}
                    formData={formData}
                    fieldsValidationErrors={fieldsValidationErrors}
                />
            )}
        </div>
    );
};

export default CustomPayment;
