import React, { useState } from 'react';
import {
    Stepper,
    type Step,
    Alert,
    ExpandableContent,
    useFullscreenModal,
    Section,
} from '@theorchard/suite-components';
import { useIdentity } from '@theorchard/suite-frontend';
import { useHistory } from 'react-router-dom';
import { type GetAccountFullDetailQuery } from 'src/apollo/queries/account/__generated__/get-account-full-detail';
import { useAccountPayeeBankDetailsQuery } from 'src/apollo/queries/account-payee-bank-details';
import { useCanPerformAction } from 'src/apollo/queries/can-perform';
import { PERMISSIONS_ACTIONS, PERMISSIONS_RESOURCE_TYPES } from 'src/constants';
import useWindowDimension from 'src/hooks/useWindowDimension';
import { paymentDetailsReviewRoute } from 'src/urls/frontend-royalties';
import { getActionStateByEventName } from 'src/utils/actionStates';
import { getLongDateFromDateTimeStamp } from 'src/utils/date-helpers';
import { popupCenter } from 'src/utils/popupCenter';
import PaymentDetailApproved from './payment-detail-approved';
import { PaymentDetailSectionHeader } from './payment-detail-section-header';
import RejectBankingDetailsModal from './reject-banking-details-modal';
import {
    ABACUS_ACTION_STATUSES,
    ABACUS_ACTIONS,
} from '@theorchard/accounting-apps-shared';
import PaymentDetailGrid from 'src/components/account-detail/payment-detail-grid';

const STEP_ICONS: Record<string, Step['icon']> = {
    WARNING: { variant: 'warning', glyphIcon: 'warning' },
    SUCCESS: { variant: 'success', glyphIcon: 'check' },
    DANGER: { variant: 'danger', glyphIcon: 'warning' },
    NEUTRAL_1: { variant: 'neutral', number: 1 },
    NEUTRAL_2: { variant: 'neutral', number: 2 },
    NEUTRAL_3: { variant: 'neutral', number: 3 },
};

type AbacusAccount = NonNullable<GetAccountFullDetailQuery['abacusAccount']>;
type AccountPayee = NonNullable<AbacusAccount['accountPayee']>;
type StepsStrategy = (params: {
    canEditBankInfo?: boolean;
    receivedDate?: string;
    reviewNotes?: string | null;
    rejectedDate?: string;
    rejectedNotes?: string | null;
    fileUploadLink?: string;
    openReviewModal?: () => void;
    openPopup: (url: string) => void;
    rejectBtn?: Step['titleAction'];
}) => Step[];

const CLASS_NAME = 'PaymentDetailWhitelabel';
export const NESTED_CLASS_NAME = `${CLASS_NAME}__nested`;
export interface PaymentDetailWhitelabelPropTypes {
    accountId: string;
    accountPayee: AccountPayee;
}

export const PaymentDetailWhitelabel: React.FC<
    PaymentDetailWhitelabelPropTypes
> = ({ accountId, accountPayee }) => {
    const history = useHistory();
    const identity = useIdentity();

    const { data: accountBankDetails } =
        useAccountPayeeBankDetailsQuery(accountId);
    const hasBankDetails =
        !!accountBankDetails?.abacusAccount?.accountPayee?.bankDetails;

    const bankDetailsModifiedAt =
        accountBankDetails?.abacusAccount?.accountPayee?.bankDetails
            ?.modifiedAt;

    const { data: canEditBankInfo } = useCanPerformAction(
        identity.id,
        PERMISSIONS_ACTIONS.EDIT,
        PERMISSIONS_RESOURCE_TYPES.BANK_INFO
    );

    const { open } = useFullscreenModal();
    const [isRejectBankingDetailsOpen, setIsRejectBankingDetailsOpen] =
        useState(false);
    const openReviewModal = () => {
        open(() => history.push(paymentDetailsReviewRoute(accountId)));
    };
    const [width, height] = useWindowDimension();
    const openPopup = (url: string) => {
        popupCenter({
            url,
            title: 'Payoneer',
            popupWidth: width - 300,
            popupHeight: height - 200,
        });
    };

    const paymentEligibility = getActionStateByEventName(
        ABACUS_ACTIONS.PAYMENT_ELIGIBILITY,
        accountPayee.actionStates
    );
    const paymentEligibilityStatus = paymentEligibility?.actionStatus;
    const bankingDetailsReview = getActionStateByEventName(
        ABACUS_ACTIONS.BANKING_DETAILS_REVIEW,
        accountPayee.actionStates
    );
    const isApproved =
        paymentEligibilityStatus === ABACUS_ACTION_STATUSES.APPROVED &&
        bankingDetailsReview?.actionStatus === ABACUS_ACTION_STATUSES.APPROVED;

    if (isApproved) {
        return (
            <PaymentDetailApproved
                accountId={accountId}
                bankDetailsModifiedAt={bankDetailsModifiedAt}
            />
        );
    }

    const rejectBtn = (canEditBankInfo && {
        label: 'REJECT',
        size: 'sm',
        variant: 'danger',
        disabled: false,
        onClick: () => setIsRejectBankingDetailsOpen(true),
    }) as Step['titleAction'] | undefined;

    return (
        <div className={CLASS_NAME} data-testid={CLASS_NAME}>
            <Section>
                <Section.Body>
                    <Section>
                        <PaymentDetailSectionHeader
                            title="Payment Details"
                            lastModified={bankDetailsModifiedAt}
                            className={`${CLASS_NAME}__header`}
                        />
                        <Section.Body>
                            <Stepper
                                steps={stepsFactory(
                                    accountPayee,
                                    openPopup,
                                    openReviewModal,
                                    rejectBtn,
                                    canEditBankInfo
                                )}
                            />
                            {!isApproved && hasBankDetails && (
                                <Section
                                    expandable
                                    className={NESTED_CLASS_NAME}
                                >
                                    <Section.Header title="Payment Data" />
                                    <Section.Body>
                                        <PaymentDetailGrid
                                            accountId={accountId}
                                        />
                                    </Section.Body>
                                </Section>
                            )}
                            <RejectBankingDetailsModal
                                accountId={accountId}
                                accountPayeeId={accountPayee.accountPayeeId}
                                isOpen={isRejectBankingDetailsOpen}
                                setIsOpen={setIsRejectBankingDetailsOpen}
                                bankingDetailsReviewStateId={
                                    bankingDetailsReview?.abacusStateId
                                }
                                paymentEligibilityStateId={
                                    paymentEligibility?.abacusStateId
                                }
                            />
                        </Section.Body>
                    </Section>
                </Section.Body>
            </Section>
        </div>
    );
};

const stepsFactory = (
    accountPayee: AccountPayee,
    openPopup: (url: string) => void,
    openReviewModal?: () => void,
    rejectBtn?: Step['titleAction'],
    canEditBankInfo: boolean = false
): Step[] => {
    const reviewAction = accountPayee?.actionStates?.find(
        item => item.actionName === ABACUS_ACTIONS.BANKING_DETAILS_REVIEW
    );
    const reviewStatus = reviewAction?.actionStatus || '';
    const reviewNotes = reviewAction?.message || '';
    const eligibilityAction = accountPayee?.actionStates?.find(
        item => item.actionName === ABACUS_ACTIONS.PAYMENT_ELIGIBILITY
    );
    const eligibilityStatus = eligibilityAction?.actionStatus || '';
    const receivedDate = getLongDateFromDateTimeStamp(
        reviewAction?.lastModified
    );
    const rejectedDate = getLongDateFromDateTimeStamp(
        eligibilityAction?.lastModified
    );
    const rejectedNotes = eligibilityAction?.message;
    const fileUploadLink =
        accountPayee.accountPayeeKycNotification?.fileUploadLink || '';

    const strategy = getStepsStrategy(reviewStatus, eligibilityStatus);

    return strategy({
        receivedDate,
        rejectedDate,
        rejectedNotes,
        fileUploadLink,
        openReviewModal,
        reviewNotes,
        openPopup,
        rejectBtn,
        canEditBankInfo,
    });
};

const getStepsStrategy = (
    reviewStatus: string,
    eligibilityStatus: string
): StepsStrategy => {
    // if banking_details_review is "RUNNING" it takes precedence over eligibilityStatus.
    // The user should be allowed to perform a reject regardless
    if (reviewStatus === ABACUS_ACTION_STATUSES.RUNNING) {
        return buildReviewRunningSteps;
    }

    const statesStepsStrategies: Record<string, StepsStrategy> = {
        [ABACUS_ACTION_STATUSES.INIT + ABACUS_ACTION_STATUSES.INIT]:
            buildReviewInitSteps,
        [ABACUS_ACTION_STATUSES.APPROVED + ABACUS_ACTION_STATUSES.INIT]:
            buildReviewApprovedSteps,
        [ABACUS_ACTION_STATUSES.REJECTED + ABACUS_ACTION_STATUSES.INIT]:
            buildReviewRejectedSteps,
        [ABACUS_ACTION_STATUSES.APPROVED + ABACUS_ACTION_STATUSES.RUNNING]:
            buildReviewApprovedSteps,
        [ABACUS_ACTION_STATUSES.APPROVED + ABACUS_ACTION_STATUSES.REJECTED]:
            buildEligibilityRejectedSteps,
    };

    return (
        statesStepsStrategies[reviewStatus + eligibilityStatus] ??
        buildDefaultSteps
    );
};

const buildDefaultSteps: StepsStrategy = (): Step[] => [
    buildStep(
        STEP_ICONS.WARNING,
        'Receipt of Bank Details',
        undefined,
        <div className="ReceptionStepBody">
            <Alert
                title="Bank details must be provided before this step can begin"
                text="Please instruct the client to enter their bank details in the Banking & Tax app."
                variant="warn"
            />
        </div>
    ),
    buildStep(
        STEP_ICONS.NEUTRAL_2,
        'Compliance Checks',
        'Status of Payoneer checks will be displayed here',
        undefined,
        undefined,
        'inactive'
    ),
    buildStep(
        STEP_ICONS.NEUTRAL_3,
        'Review Bank Details',
        'Once KYC process is completed you will be able to review banking details',
        undefined,
        { label: 'REVIEW', size: 'sm', variant: 'primary', disabled: true },
        'inactive'
    ),
];

const buildReviewInitSteps: StepsStrategy = ({ receivedDate }): Step[] => [
    buildStep(
        STEP_ICONS.SUCCESS,
        'Receipt of Bank Details',
        `Received on ${receivedDate}`
    ),
    buildStep(
        STEP_ICONS.WARNING,
        'Compliance Checks',
        undefined,
        <div className="ReceptionStepBody">
            <Alert
                text="Payoneer's automated KYC checks are in progress."
                variant="warn"
            />
        </div>
    ),
    buildStep(
        STEP_ICONS.NEUTRAL_3,
        'Review Bank Details',
        'Once KYC process is completed you will be able to review banking details',
        undefined,
        { label: 'REVIEW', size: 'sm', variant: 'primary', disabled: true },
        'inactive'
    ),
];

const buildReviewRunningSteps: StepsStrategy = ({
    receivedDate,
    fileUploadLink,
    openPopup,
    rejectBtn,
    canEditBankInfo,
}): Step[] => {
    // Solfege Alert.link has a router Link under the hood and types collision where only
    // string is allowed to pass to it, so impossible to link the external resource as is.
    const alertText = canEditBankInfo ? (
        <div>
            <div>
                Please follow the link to confirm next steps and to upload any
                requested client documentation.
            </div>
            <div className="alert-text-link">
                <a
                    onClick={e => {
                        e.preventDefault();
                        openPopup(fileUploadLink as string);
                    }}
                    href={fileUploadLink}
                >
                    Upload documentation to Payoneer
                </a>
            </div>
        </div>
    ) : (
        ''
    );

    return [
        buildStep(
            STEP_ICONS.SUCCESS,
            'Receipt of Bank Details',
            `Received on ${receivedDate}`
        ),
        buildStep(
            STEP_ICONS.DANGER,
            'Compliance Checks',
            undefined,
            <div className="ReceptionStepBody">
                <Alert
                    title="Bank details did not automatically pass Payoneer's KYC checks"
                    text={alertText}
                    variant="error"
                />
            </div>,
            rejectBtn
        ),
        buildStep(
            STEP_ICONS.NEUTRAL_3,
            'Review Bank Details',
            'Once KYC process is completed you will be able to review banking details',
            undefined,
            { label: 'REVIEW', size: 'sm', variant: 'primary', disabled: true },
            'inactive'
        ),
    ];
};

const buildReviewApprovedSteps: StepsStrategy = ({
    receivedDate,
    openReviewModal,
}): Step[] => [
    buildStep(
        STEP_ICONS.SUCCESS,
        'Receipt of Bank Details',
        `Received on ${receivedDate}`
    ),
    buildStep(
        STEP_ICONS.SUCCESS,
        'Compliance Checks',
        `Bank details have passed KYC checks`
    ),
    buildStep(STEP_ICONS.WARNING, 'Review Bank Details', undefined, undefined, {
        label: 'REVIEW',
        size: 'sm',
        variant: 'primary',
        onClick: openReviewModal,
    }),
];

const buildReviewRejectedSteps: StepsStrategy = ({ reviewNotes }): Step[] => {
    return [
        buildStep(
            STEP_ICONS.WARNING,
            'Receipt of Bank Details',
            undefined,
            <div className="ReceptionStepBody">
                <Alert
                    title="Request client new bank details"
                    text="Please instruct the client to re-submit their bank details in the Banking & Tax app."
                    variant="warn"
                />
            </div>
        ),
        buildStep(
            STEP_ICONS.DANGER,
            'Compliance Checks',
            undefined,
            <div className="ReceptionStepBody">
                <Alert
                    title="Bank details did not automatically pass Payoneer's KYC checks"
                    text={`KYC check failed because of ${reviewNotes}`}
                    variant="error"
                />
            </div>
        ),
        buildStep(
            STEP_ICONS.NEUTRAL_3,
            'Review Bank Details',
            'Once KYC process is completed you will be able to review banking details',
            undefined,
            { label: 'REVIEW', size: 'sm', variant: 'primary', disabled: true },
            'inactive'
        ),
    ];
};

const buildEligibilityRejectedSteps: StepsStrategy = ({
    rejectedDate,
    rejectedNotes,
}): Step[] => [
    buildStep(
        STEP_ICONS.WARNING,
        'Receipt of Bank Details',
        undefined,
        <div className="ReceptionStepBody">
            <Alert
                title="Bank details must be provided before this step can begin"
                text="Please instruct the client to enter their bank details in the Banking & Tax app."
                variant="warn"
            />
        </div>
    ),
    buildStep(
        STEP_ICONS.WARNING,
        'Compliance Checks',
        'To get Payoneer to complete the checks you need the banking details',
        undefined,
        undefined,
        'inactive'
    ),
    buildStep(
        STEP_ICONS.DANGER,
        'Review Bank Details',
        undefined,
        <div className="ReviewStepBody">
            {`Rejected on ${rejectedDate}`}
            {rejectedNotes && (
                <ExpandableContent className="mt-3" expandLabel="SEE NOTES">
                    {rejectedNotes}
                </ExpandableContent>
            )}
        </div>,
        { label: 'REVIEWED', size: 'sm', variant: 'secondary', disabled: true },
        'rejected'
    ),
];

const buildStep = (
    icon: Step['icon'],
    title: string,
    description?: string,
    body?: Step['body'],
    titleAction?: Step['titleAction'],
    className?: string
): Step => ({ icon, title, description, titleAction, className, body });
