import React, { useEffect, useState } from 'react';
import {
    Alert,
    Button,
    type DropdownOption,
    SegmentedButton,
} from '@theorchard/suite-components';
import {
    type QueryParamsConfig,
    useFeatureFlag,
} from '@theorchard/suite-frontend';
import BigNumber from 'bignumber.js';
import { trim } from 'lodash-es';
import { Link, useHistory, useLocation } from 'react-router-dom';
import { type CreatePaymentGroupMutationVariables } from 'src/apollo/mutations/__generated__/payment-group';
import { useCreateWorksheetPaymentContractAdvance } from 'src/apollo/mutations/contract-advance';
import { type CreateWorksheetPaymentContractAdvanceMutationVariables } from 'src/apollo/mutations/contract-advance/__generated__/create-worksheet-payment-contract-advance';
import { useCreateCustomPayment } from 'src/apollo/mutations/custom-payment/create-custom-payment';
import { useCreatePaymentGroup } from 'src/apollo/mutations/payment-group';
import { useCreatePaymentGroupPayment } from 'src/apollo/mutations/payment-group-payment';
import { type CreatePaymentGroupPaymentMutationVariables } from 'src/apollo/mutations/payment-group-payment/__generated__/create-payment-group-payment';
import { usePaymentGroupsList } from 'src/apollo/queries/payment-group';
import CustomPayment from 'src/components/payment-group-form/custom-payment';
import PaymentExistingGroup from 'src/components/payment-group-form/payment-existing-group';
import PaymentSpecificAccount from 'src/components/payment-group-form/payment-specific-account';
import PaymentSpecificAdvance from 'src/components/payment-group-form/payment-specific-advance';
import { PageHeader } from 'src/components/shared/pageHeader';
import {
    EXISTING_GROUP,
    SPECIFIC_ADVANCE,
    SPECIFIC_GROUP,
    CUSTOM_PAYMENT,
    USER_FEATURES,
} from 'src/constants';
import { getPaymentBreadcrumbs } from 'src/hooks/breadcrumbs/payment';
import { type ChangeHandlerArgs } from 'src/types/change-handler';
import {
    getAdvancePaymentDetail,
    getCustomPaymentDetail,
    getPaymentGroupPaymentDetail,
    getPaymentsListPage,
} from 'src/urls/frontend-royalties';
import { getQueryParams, updateQueryParam } from 'src/utils/route';
import type * as Types from 'src/apollo/definitions/globalTypes';
import type {
    PaymentGroupFormData,
    PaymentSpecificAdvanceParsedParams,
} from 'src/types/payment-group-form';
import './styles.scss';

interface ErrorState {
    validation?: string;
    serverError?: string;
    fieldsValidation?: Record<string, string>;
}

const getErrorMessage = (errors: ErrorState) => {
    return errors.validation ?? errors.serverError ?? null;
};

export default function PaymentGroupForm() {
    const [disableContinueBtn, setDisableContinueBtn] = useState(true);
    const [errors, setErrors] = useState<ErrorState>({});
    const [existingPaymentGroups, setExistingPaymentGroups] = useState<
        DropdownOption[]
    >([]);
    const [formData, setFormData] = useState<PaymentGroupFormData>({});
    const [accountName, setAccountName] = useState<string | undefined>('');
    const [paymentGroupMethod, setPaymentGroupMethod] =
        useState(EXISTING_GROUP);
    const reusableOnly = true;
    const limit = 300;
    const offset = 0;

    const history = useHistory();
    const location = useLocation();
    const breadcrumbs = getPaymentBreadcrumbs('New Payment');

    const addPaymentGroup = useCreatePaymentGroup(paymentGroupMethod);
    const addPaymentGroupPayment = useCreatePaymentGroupPayment();
    const createWorksheetPaymentContractAdvance =
        useCreateWorksheetPaymentContractAdvance();
    const { createCustomPayment } = useCreateCustomPayment();
    const isTapDraftPaymentsEnabled = useFeatureFlag(
        USER_FEATURES.ABACUS_TAP_DRAFT_PAYMENTS
    );

    const TABS = [
        EXISTING_GROUP,
        SPECIFIC_GROUP,
        SPECIFIC_ADVANCE,
        CUSTOM_PAYMENT,
    ];

    const { data: paymentGroups } = usePaymentGroupsList({
        reusableOnly,
        limit,
        offset,
    });

    const queryParams: QueryParamsConfig = {
        selectTab: {
            name: 'selectTab',
            type: 'string',
        },
        contractId: {
            name: 'contractId',
            type: 'string',
        },
        contractAdvanceId: {
            name: 'contractAdvanceId',
            type: 'string',
        },
        advanceDescription: {
            name: 'advanceDescription',
            type: 'string',
        },
        referencePaymentTypeId: {
            name: 'referencePaymentTypeId',
            type: 'string',
        },
    };

    const parsedParams: PaymentSpecificAdvanceParsedParams = getQueryParams(
        location,
        queryParams
    );

    const changeHandler = (e: ChangeHandlerArgs) => {
        const { name = '', value } = e.target ?? {};
        setErrors({});
        setFormData(prev => {
            if (prev[name] === value) return prev;

            return { ...prev, [name]: value } as PaymentGroupFormData;
        });
    };

    const paymentGroupClickHandler = (method: string) => {
        updateQueryParam(location, history, queryParams, 'selectTab', method);
        switch (method) {
            case EXISTING_GROUP: {
                setFormData({ paymentGroupId: '', paymentName: '' });
                setErrors({});
                break;
            }
            case SPECIFIC_GROUP: {
                const initialData = {
                    accountOptions: [],
                    paymentName: '',
                    groupName: '',
                };
                setFormData(initialData);
                setErrors({});
                break;
            }
            case CUSTOM_PAYMENT: {
                const initialData = {
                    accountOption: { value: '' },
                    contractId: '',
                    activityStatementPeriodId: '',
                    statementPeriodId: '',
                    amount: '',
                    withholdingTaxAmount: '',
                    withholdingTaxRate: '',
                    vatAmount: '',
                    vatRate: '',
                    paymentName: '',
                    currency: '',
                };
                setFormData(initialData);
                setErrors({});
                break;
            }
            default:
                break;
        }

        setPaymentGroupMethod(method);
    };

    useEffect(() => {
        setPaymentGroupMethod(parsedParams.selectTab || EXISTING_GROUP);
    }, [parsedParams]);

    const renderGroupButtons = () => (
        <SegmentedButton
            onChange={val => paymentGroupClickHandler(val)}
            variant="primary"
            value={paymentGroupMethod}
        >
            {TABS.map(method => (
                <SegmentedButton.Text key={`${method}-btn`} id={method}>
                    {method}
                </SegmentedButton.Text>
            ))}
        </SegmentedButton>
    );

    const submitHandler = () => {
        setDisableContinueBtn(true);
        if (paymentGroupMethod === EXISTING_GROUP) {
            const variables: CreatePaymentGroupPaymentMutationVariables = {
                paymentGroupId: formData.paymentGroupId ?? '',
                paymentName: trim(formData.paymentName),
            };

            addPaymentGroupPayment({ variables })
                .then(({ data }) => {
                    const { paymentGroupPaymentId } =
                        data?.abacusCreatePaymentGroupPayment ?? {};
                    history.push(
                        getPaymentGroupPaymentDetail(paymentGroupPaymentId)
                    );
                })
                .catch(err => {
                    setDisableContinueBtn(false);
                    setErrors({
                        serverError: err[0].message || JSON.stringify(err),
                    });
                });
        } else if (paymentGroupMethod === SPECIFIC_GROUP) {
            const accountOptions = formData?.accountOptions ?? [];
            const accountIds = accountOptions.map(o => o.value);
            const groupCriteria = { accountIds };
            let groupName = trim(accountName);

            groupName =
                accountIds.length > 1
                    ? 'Multiple accounts'
                    : trim(accountOptions[0]?.label);

            const variables: CreatePaymentGroupMutationVariables = {
                groupCriteria,
                groupName,
                paymentName: trim(formData.paymentName),
            };
            addPaymentGroup({ variables })
                .then(({ data }) => {
                    const { paymentGroupPaymentId } =
                        data?.abacusCreatePaymentGroup ?? {};
                    history.push(
                        getPaymentGroupPaymentDetail(paymentGroupPaymentId)
                    );
                })
                .catch(err => {
                    setDisableContinueBtn(false);
                    setErrors({
                        serverError: err[0]?.message || JSON.stringify(err),
                    });
                });
        } else if (paymentGroupMethod === SPECIFIC_ADVANCE) {
            const variables: CreateWorksheetPaymentContractAdvanceMutationVariables =
                {
                    contractAdvanceId:
                        formData.specificAdvance?.contractAdvanceId ?? '',
                    paymentName:
                        formData.specificAdvance?.paymentName?.trim() ?? '',
                };
            createWorksheetPaymentContractAdvance({ variables })
                .then(({ data }) => {
                    history.push(
                        getAdvancePaymentDetail(
                            data?.createWorksheetPaymentContractAdvance
                                .worksheetPaymentContractAdvanceId
                        )
                    );
                })
                .catch(err => {
                    setDisableContinueBtn(false);
                    setErrors({
                        serverError: err[0].message || JSON.stringify(err),
                    });
                });
        } else if (paymentGroupMethod === CUSTOM_PAYMENT) {
            const {
                accountOption,
                amount,
                withholdingTaxAmount,
                withholdingTaxRate,
                paymentName,
                vatAmount,
                vatRate,
                activityStatementPeriodId = '',
                statementPeriodId = '',
                contractId = '',
                currency,
            } = formData;
            const _amount = trim(amount);
            const _vatAmount = trim(vatAmount) || '0';
            const _vatRate = trim(vatRate) || '0';
            const _withholdingTaxAmount = trim(withholdingTaxAmount) || '0';
            const _withholdingTaxRate = trim(withholdingTaxRate) || '0';
            const amountAfterWithholdingAndVat = BigNumber(_amount)
                .plus(_vatAmount || 0)
                .plus(_withholdingTaxAmount || 0);

            let validation = undefined;
            if (!amountAfterWithholdingAndVat.isGreaterThan(0)) {
                validation = 'Total payment amount must be greater than 0.';
            }

            const fieldsValidation: Record<string, string> = {};

            const checkAmountAndRate = (
                amount: string | null,
                rate: string | null,
                amountField: string,
                rateField: string,
                amountMsg: string,
                rateMsg: string
            ) => {
                if (
                    !BigNumber(amount || 0).isEqualTo(0) &&
                    BigNumber(rate || 0).isEqualTo(0)
                ) {
                    fieldsValidation[rateField] = rateMsg;
                }
                if (
                    !BigNumber(rate || 0).isEqualTo(0) &&
                    BigNumber(amount || 0).isEqualTo(0)
                ) {
                    fieldsValidation[amountField] = amountMsg;
                }
            };

            checkAmountAndRate(
                _withholdingTaxAmount,
                _withholdingTaxRate,
                'withholdingTaxAmount',
                'withholdingTaxRate',
                'WHT amount is required for WHT rate.',
                'Rate is required for WHT amount.'
            );

            checkAmountAndRate(
                _vatAmount,
                _vatRate,
                'vatAmount',
                'vatRate',
                'VAT amount is required for VAT rate.',
                'Rate is required for VAT amount.'
            );

            if (validation || Object.keys(fieldsValidation).length > 0) {
                setErrors({ validation, fieldsValidation });
                setDisableContinueBtn(true);

                return;
            }

            const variables: Types.createCustomPaymentInput = {
                contractId,
                activityStatementPeriodId,
                accountId: accountOption?.value ?? '',
                amount: _amount,
                withholdingTaxAmount: _withholdingTaxAmount,
                withholdingTaxRate: _withholdingTaxRate,
                currencyCode: currency ?? '',
                paymentName: trim(paymentName),
                vatAmount: _vatAmount,
                vatRate: _vatRate,
                amountAfterWithholdingAndVat:
                    amountAfterWithholdingAndVat.toString(),
                statementPeriodId,
            };

            createCustomPayment({
                variables: {
                    input: variables,
                },
            })
                .then(({ data }) => {
                    history.push(
                        getCustomPaymentDetail(
                            data?.createCustomPayment.worksheetPaymentCustomId
                        )
                    );
                })
                .catch(err => {
                    setDisableContinueBtn(false);
                    setErrors({
                        serverError:
                            err.message ||
                            err[0].message ||
                            JSON.stringify(err),
                    });
                });
        }
    };

    useEffect(() => {
        if (paymentGroups && paymentGroups.abacusPaymentGroups) {
            const { items } = paymentGroups.abacusPaymentGroups;
            const groupLists: DropdownOption[] = items.map(group => ({
                value: group?.paymentGroupId ?? '',
                label: group?.groupName,
            }));
            setExistingPaymentGroups(groupLists);
        }
    }, [paymentGroups]);

    const validateFields = (isConditionValid: boolean | string) => {
        if (isConditionValid) setDisableContinueBtn(false);
        else setDisableContinueBtn(true);
    };

    useEffect(() => {
        const { paymentGroupId, paymentName, specificAdvance } = formData;

        const contractAdvanceId = specificAdvance?.contractAdvanceId;
        const specificAdvancePaymentName = specificAdvance?.paymentName;

        switch (paymentGroupMethod) {
            case EXISTING_GROUP: {
                validateFields(trim(paymentGroupId) && trim(paymentName));
                break;
            }
            case SPECIFIC_GROUP: {
                const accountOptions =
                    formData?.accountOptions?.filter(option => option.value) ||
                    [];
                const hasIds = accountOptions.length > 0;
                validateFields(hasIds && trim(paymentName));
                break;
            }
            case SPECIFIC_ADVANCE: {
                validateFields(
                    trim(contractAdvanceId) && trim(specificAdvancePaymentName)
                );
                break;
            }
            case CUSTOM_PAYMENT: {
                const {
                    accountOption,
                    currency,
                    amount,
                    contractId,
                    paymentName,
                    activityStatementPeriodId,
                    statementPeriodId,
                } = formData;
                const hasAccount = !!accountOption;
                const hasCurrency = !!currency;
                const hasContract = !!contractId;
                const hasActivityStatementPeriod = !!activityStatementPeriodId;
                const hasStatementPeriodId = !!statementPeriodId;
                const hasName = !!trim(paymentName);
                const hasAmount = !!trim(amount);

                validateFields(
                    hasAccount &&
                        hasCurrency &&
                        hasContract &&
                        hasName &&
                        hasAmount &&
                        hasActivityStatementPeriod &&
                        hasStatementPeriodId
                );
                break;
            }
            default:
                break;
        }
    }, [SPECIFIC_GROUP, formData, paymentGroupMethod]);

    const errorMessage = getErrorMessage(errors);

    return (
        // TODO: remove `redesign` className when redesign is complete
        <div className="PaymentGroup PaymentGroupForm redesign">
            <PageHeader title="New Payment" breadcrumbs={breadcrumbs} />
            {errorMessage && <Alert variant="error" text={errorMessage} />}
            <div className="card">
                <div className="PaymentGroupFormFields PaymentGroupFormFieldsRedesign">
                    <div className="PaymentGroupFormPaymentMethod">
                        <p>Select Method</p>
                        {renderGroupButtons()}
                    </div>
                    {paymentGroupMethod === EXISTING_GROUP && (
                        <PaymentExistingGroup
                            changeHandler={changeHandler}
                            existingPaymentGroups={existingPaymentGroups}
                        />
                    )}
                    {paymentGroupMethod === SPECIFIC_GROUP && (
                        <PaymentSpecificAccount
                            changeHandler={changeHandler}
                            formData={formData}
                            setAccountName={setAccountName}
                        />
                    )}
                    {paymentGroupMethod === SPECIFIC_ADVANCE && (
                        <PaymentSpecificAdvance
                            changeHandler={changeHandler}
                            formData={formData}
                            setFormData={setFormData}
                            parsedParams={parsedParams}
                        />
                    )}

                    {paymentGroupMethod === CUSTOM_PAYMENT && (
                        <CustomPayment
                            changeHandler={changeHandler}
                            formData={formData}
                            fieldsValidationErrors={errors.fieldsValidation}
                        />
                    )}
                </div>
            </div>

            <div className="buttons">
                <Link to={getPaymentsListPage}>
                    <Button className="btn-cancel">Cancel</Button>
                </Link>
                <Button
                    onClick={submitHandler}
                    variant="primary"
                    disabled={disableContinueBtn}
                >
                    {isTapDraftPaymentsEnabled &&
                    [EXISTING_GROUP, SPECIFIC_GROUP].includes(
                        paymentGroupMethod
                    )
                        ? 'Save As Draft'
                        : 'Create'}
                </Button>
            </div>
        </div>
    );
}
