import React, { useContext, useEffect, useState } from 'react';
import type { UploadAreaInfoProps } from '@theorchard/suite-components';
import {
    Alert,
    FullscreenModal,
    UploadArea,
} from '@theorchard/suite-components';
import { isEmpty } from 'lodash-es';
import { ABACUS_ACTION_STATUSES } from '@theorchard/accounting-apps-shared';

import {
    AbacusDag,
    AbacusFileUploadStatus,
} from 'src/apollo/definitions/globalTypes';
import { useDagRunTimesQuery } from 'src/apollo/queries/dag-run-times';
import { STATEMENT_PERIOD_ADJUSTMENT_UPLOAD_ACTIONS } from 'src/constants';
import { formatFileFromFileUpload } from 'src/utils/adjustment-file';
import { AdjustmentsContext } from 'src/contexts/adjustments-context';
import type { GetStatementPeriodAdjustmentFileAndStatesQuery } from 'src/apollo/queries/adjustment/__generated__/statement-period-adjustment-file-and-states';
import RunTimerTooltip from 'src/components/shared/run-timer-tooltip';
import { useGetAbacusFileUpload } from 'src/apollo/queries/abacus-file-upload/get-abacus-file-upload';
import { useGetAbacusFileUploadAdjustmentFile } from 'src/apollo/queries/abacus-file-upload/get-abacus-file-upload-adjustment-file';

type AbacusStatementPeriodAdjustmentFile = NonNullable<
    GetStatementPeriodAdjustmentFileAndStatesQuery['abacusStatementPeriodAdjustmentFile']
>;
type ActionStateTypes =
    AbacusStatementPeriodAdjustmentFile['actionStates'] extends
        | (infer T)[]
        | null
        ? T
        : null;

export const FILE_UPLOAD_POLLING_INTERVAL = 5000;
export const ADJUSTMENT_FILE_APPROVING_POLLING_INTERVAL = 5000;

const AdjustmentsUploadLoadingScreenWithAbacusFileUpload = () => {
    const {
        setModalState,
        adjustmentFile,
        setAdjustmentFile,
        setStatementPeriodAdjustmentFileId,
    } = useContext(AdjustmentsContext);

    const [uploadStatus, setUploadStatus] = useState<
        ActionStateTypes | undefined | null
    >(undefined);

    const {
        data: fileData,
        startPolling: startApprovalPolling,
        stopPolling: stopApprovalPolling,
    } = useGetAbacusFileUploadAdjustmentFile(adjustmentFile!.uploadFileKey!);

    const {
        data: fileUploadData,
        startPolling: startAbacusFileUploadPolling,
        stopPolling: stopAbacusFileUploadPolling,
    } = useGetAbacusFileUpload(adjustmentFile!.uploadFileKey!);

    const { data: uploadFileDagRunTimes } = useDagRunTimesQuery(
        AbacusDag.ADJUSTMENT_FILE_UPLOAD
    );

    const avgUploadTime =
        uploadFileDagRunTimes?.abacusDagRunTimes.averageRunTimeSeconds;

    const p95UploadTime =
        uploadFileDagRunTimes?.abacusDagRunTimes.p95RunTimeSeconds;

    useEffect(() => {
        if (!isEmpty(uploadStatus)) {
            if (uploadStatus!.actionStatus === ABACUS_ACTION_STATUSES.ERROR) {
                stopApprovalPolling();
                setAdjustmentFile(formatFileFromFileUpload(fileData!));
                setModalState(ABACUS_ACTION_STATUSES.ERROR);
            }

            if (
                uploadStatus!.actionStatus === ABACUS_ACTION_STATUSES.COMPLETE
            ) {
                stopApprovalPolling();
                setAdjustmentFile(formatFileFromFileUpload(fileData!));
                setModalState(ABACUS_ACTION_STATUSES.COMPLETE);
            }
        }
    }, [uploadStatus]);

    useEffect(() => {
        if (
            fileData &&
            fileData.abacusFileUpload?.statementPeriodAdjustmentFile
        ) {
            setStatementPeriodAdjustmentFileId(
                fileData.abacusFileUpload.statementPeriodAdjustmentFile
                    .statementPeriodAdjustmentFileId
            );
            const { actionStates } =
                fileData.abacusFileUpload.statementPeriodAdjustmentFile;

            if (!isEmpty(actionStates)) {
                setUploadStatus(
                    actionStates?.find(
                        action =>
                            action!.actionName ===
                            STATEMENT_PERIOD_ADJUSTMENT_UPLOAD_ACTIONS.UPLOAD_FILE
                    )
                );
            }
        }
    }, [fileData]);

    useEffect(() => {
        startAbacusFileUploadPolling(FILE_UPLOAD_POLLING_INTERVAL);

        if (fileUploadData) {
            if (
                fileUploadData?.abacusFileUpload?.uploadStatus ===
                AbacusFileUploadStatus.COMPLETE
            ) {
                stopAbacusFileUploadPolling();
                startApprovalPolling(
                    ADJUSTMENT_FILE_APPROVING_POLLING_INTERVAL
                );
            }
            if (
                fileUploadData?.abacusFileUpload?.uploadStatus ===
                    AbacusFileUploadStatus.CANCELLED ||
                fileUploadData.abacusFileUpload?.uploadStatus ===
                    AbacusFileUploadStatus.ERROR ||
                fileUploadData.abacusFileUpload?.uploadStatus ===
                    AbacusFileUploadStatus.QUARANTINED
            ) {
                stopAbacusFileUploadPolling();
                setModalState(ABACUS_ACTION_STATUSES.ERROR);
            }
        }

        return () => {
            stopAbacusFileUploadPolling();
        };
    }, [fileUploadData]);

    const getUploadAreaInfo = (): UploadAreaInfoProps => {
        return {
            illustration: 'spinner',
            title: 'Validating Your File',
            description: 'Checking for data integrity...',
        };
    };

    const renderUploadArea = () => (
        <UploadArea
            disabled
            inputId="browser-upload-loading"
            info={getUploadAreaInfo()}
            onUpload={() => {
                return;
            }}
            testId="AdjustmentsUploadLoadingArea"
            variant="large"
        />
    );

    return (
        <>
            <FullscreenModal.Title title="Uploading File" />
            <FullscreenModal.Body>
                <Alert
                    testId="AdjustmentsUploadingFileAlert"
                    variant="information"
                    text={
                        <span>
                            <b>
                                Please stay on this page while your file
                                uploads.
                            </b>
                            <br />
                            Closing or leaving this page will cancel your
                            upload. To ensure it completes successfully, please
                            remain here until it finishes.
                        </span>
                    }
                />
                {avgUploadTime && p95UploadTime ? (
                    <RunTimerTooltip
                        avgRunTime={avgUploadTime}
                        p95RunningTime={p95UploadTime}
                        tooltipLocation="bottom"
                        testId="AdjustmentsUploadingRunTimerTooltip"
                    >
                        {renderUploadArea()}
                    </RunTimerTooltip>
                ) : (
                    renderUploadArea()
                )}
            </FullscreenModal.Body>
        </>
    );
};

export default AdjustmentsUploadLoadingScreenWithAbacusFileUpload;
