import type { FC } from 'react';
import React, { useCallback, useState } from 'react';
import {
    LoadingSpinner,
    Alert,
    UploadArea,
} from '@theorchard/suite-components';
import { useIdentity } from '@theorchard/suite-frontend';
import { useLazyUploadToken } from 'src/data/queries';
import { uploadFileToS3 } from 'src/utils/aws';
import { useUpload } from 'src/utils/features';
import { normalizeFilename } from 'src/utils/formatter';
import {
    recordTemplateDownloadClick,
    recordUploadFile,
} from 'src/utils/segment/segment';
import {
    CORRECT_COLUMN_HEADERS,
    REQUIRED_COLUMNS,
    TOTAL_COLUMN_COUNT,
} from './constants';
import UploadGlyph from './uploadIcon';
import { validateCsvData } from './validator';
import type { FileError } from './validator';
import type { NrToken } from 'src/data/queries/nrUploadToken/types';

export const CLASSNAME = 'UploadBox';

export interface Props {
    accept: string[];
    handleFileErrors: (err: FileError) => void;
    handleS3Uploaded: (filename: string | null) => void;
}

const UploadBox: FC<Props> = ({
    accept,
    handleFileErrors,
    handleS3Uploaded,
}) => {
    const { profileId, id, profileUUID } = useIdentity();
    const [doGetUploadToken, { data: uploadToken }] = useLazyUploadToken({
        originalFilename: '',
    });

    const [validFile, setValidFile] = useState<File>();
    const [startS3FileUpload, setStartS3FileUpload] = useState<boolean>(false);
    const [isS3Uploading, setIsS3Uploading] = useState<boolean>(false);
    const [showUpload] = useState<boolean>(useUpload());
    const [fileName, setFileName] = useState<string>('');
    const handleFileTypeError = (item?: FileError[]) => {
        if (!item) return;

        handleFileErrors(item[0]); // Return error for that single file.
    };

    const handleFileValidation = useCallback(
        async (items?: File[]) => {
            if (!items || items.length < 1) return;

            const schemaErrors = await validateCsvData(
                items[0],
                CORRECT_COLUMN_HEADERS,
                REQUIRED_COLUMNS,
                TOTAL_COLUMN_COUNT
            );

            if (schemaErrors)
                handleFileErrors({ errors: schemaErrors, file: items[0] });
            else {
                setFileName(normalizeFilename(items[0].name));
                setValidFile(items[0]);
                void doGetUploadToken({
                    variables: { originalFilename: fileName },
                });
            }
        },
        [handleFileErrors, setValidFile, doGetUploadToken, fileName]
    );

    const onStartUpload = (files: File[]) => {
        void handleFileValidation(files);
        setStartS3FileUpload(true);
    };

    if (
        !isS3Uploading &&
        validFile &&
        uploadToken &&
        startS3FileUpload &&
        fileName
    ) {
        setIsS3Uploading(true);
        const token: NrToken = uploadToken.nrUploadToken;
        const fileExtension = fileName.split('.').pop();
        const key = `${token.filename}.${fileExtension}`;

        void uploadFileToS3(validFile, token.bucket, key, token.credentials, {
            filename: fileName,
            profileId: `${profileId}`,
            identityId: `${id}`,
            profileUUID: `${profileUUID}`,
        })
            .catch(error => {
                handleFileErrors({
                    errors: [{ message: error.message, code: error.code }],
                    file: validFile,
                });
            })
            .then(() => {
                setStartS3FileUpload(false);
                setIsS3Uploading(false);
            })
            .finally(() => {
                handleS3Uploaded(key);
                recordUploadFile();
            });
    }

    return (
        <div>
            {!isS3Uploading && (
                <div className={`${CLASSNAME}-instructions`}>
                    <p>
                        {$t(
                            `neighbouringRights.uploadBox.uploadCsvInstructions`
                        )}
                        <a
                            onClick={recordTemplateDownloadClick}
                            href="https://cdn.theorchard.io/assets/frontend-content/blank_nr_master_importer.csv"
                        >
                            <b>
                                <i data-testid="templateLink">
                                    {$t(
                                        `neighbouringRights.uploadBox.templateLink`
                                    )}
                                </i>
                            </b>
                        </a>
                    </p>
                </div>
            )}
            {isS3Uploading && (
                <Alert
                    variant="information"
                    text={
                        <span>
                            {$t(`neighbouringRights.uploadBox.stayOnPage`)}
                        </span>
                    }
                />
            )}
            <UploadArea
                onUpload={onStartUpload}
                onDropRejected={handleFileTypeError}
                accept={accept}
                maxFiles={1}
                multipleFileSelection={false}
                className={CLASSNAME}
                inputId="csv-browser-upload"
                disabled={!showUpload}
            >
                {!showUpload && (
                    <div
                        className={`${CLASSNAME}-s3-uploading`}
                        data-testid="hide-upload"
                    >
                        <div className={`${CLASSNAME}-hide-uploading-message`}>
                            <h2 data-testid="hide-uploading-message">
                                {$t(`neighbouringRights.uploadBox.hideUpload`)}
                            </h2>
                        </div>
                    </div>
                )}
                {!isS3Uploading && !startS3FileUpload && showUpload && (
                    <div
                        className={`${CLASSNAME}-area`}
                        data-testid="upload-area"
                    >
                        <h2 className={`${CLASSNAME}-header-text`}>
                            {$t(`neighbouringRights.uploadBox.uploadYourFile`)}
                        </h2>
                        <div className={`${CLASSNAME}-help-text`}>
                            {$t(`neighbouringRights.uploadBox.dragDropMessage`)}
                            <label
                                data-testid={CLASSNAME}
                                htmlFor="csv-browser-upload"
                                className={`${CLASSNAME}-browse-link`}
                            >
                                {$t(`neighbouringRights.uploadBox.browse`)}
                            </label>
                            {$t(`neighbouringRights.uploadBox.fromComputer`)}
                        </div>
                        <UploadGlyph />
                    </div>
                )}
                {isS3Uploading && startS3FileUpload && (
                    <div
                        className={`${CLASSNAME}-s3-uploading`}
                        data-testid="uploading-file"
                    >
                        <div className={`${CLASSNAME}-uploading-message`}>
                            <h2>
                                {$t(`neighbouringRights.uploadBox.uploading`)}
                            </h2>
                            <LoadingSpinner show />
                        </div>
                        <div className={`${CLASSNAME}-uploading-files`}>
                            <p>
                                {$t(
                                    `neighbouringRights.uploadBox.runningReview`
                                )}{' '}
                                {validFile?.name}
                            </p>
                        </div>
                    </div>
                )}
            </UploadArea>
        </div>
    );
};

export default UploadBox;
