import React, { useEffect, useState } from 'react';
import { Alert, Section } from '@theorchard/suite-components';
import { EntityBulkEditTable } from 'src/components/contract-bulk-edit/common/entity-bulk-edit-table';
import EntityBulkEditProcessingStatus from 'src/components/contract-bulk-edit/common/entity-bulk-edit-processing-status';
import { useApolloClient } from '@apollo/client';
import {
    BulkEditEntryBase,
    BulkSchema,
} from 'src/components/contract-bulk-edit/common/edit-schema/common-bulk-edit-schema';
import EntityBulkEditApplyButton from 'src/components/contract-bulk-edit/common/entity-bulk-edit-apply-button';
import EntityBulkEditSupportedUpdateSchemas from 'src/components/contract-bulk-edit/common/entity-bulk-edit-supported-update-schemas';
import { selectSchemaByColumns } from 'src/components/contract-bulk-edit/common/edit-schema/bulk-edit-schema-registry';
import EntityBulkEditTemplateDownload from 'src/components/contract-bulk-edit/common/entity-bulk-edit-template-download';

export interface EntityBulkEditFileInfoPropTypes {
    bulkEditFile: File | null;
}

const parseFile = async (file: File) => {
    const [data, XLSX] = await Promise.all([
        file.arrayBuffer(),
        import(/* webpackChunkName: "xlsx" */ 'xlsx'),
    ]);

    const workbook = XLSX.read(data, {
        type: 'string',
        raw: true,
    });

    // first sheet
    const sheetName = workbook.SheetNames[0];
    const sheet = workbook.Sheets[sheetName];

    // get all column names from first row
    const range = XLSX.utils.decode_range(sheet['!ref'] || 'A1');
    const columnNames: string[] = [];

    for (let col = range.s.c; col <= range.e.c; col++) {
        const cellAddress = XLSX.utils.encode_cell({ r: range.s.r, c: col });
        const cellValue = sheet[cellAddress]?.v || '';
        columnNames.push(cellValue);
    }

    // convert to JSON
    const lowerCaseKeys = (row: Record<string, any>) =>
        Object.fromEntries(
            Object.entries(row).map(([key, value]) => [
                key.toLowerCase(),
                value,
            ])
        );

    const rows: any[] = XLSX.utils.sheet_to_json(sheet);
    const jsonData = rows.map(lowerCaseKeys);

    return { jsonData, columnNames };
};

export const EntityBulkEditFileInfo: React.FC<
    EntityBulkEditFileInfoPropTypes
> = props => {
    const [error, setError] = useState<string | null>(null);
    const [page, setPage] = useState<number>(0);
    const [pageSize, setPageSize] = useState<number>(20);
    const [success, setSuccess] = useState<BulkEditEntryBase[]>([]);
    const [failed, setFailed] = useState<
        {
            entry: BulkEditEntryBase;
            error: any;
            message: string | null;
        }[]
    >([]);
    const [isLoading, setIsLoading] = useState<boolean>(false);

    const [bulkEditEntries, setBulkEditEntries] = useState<BulkEditEntryBase[]>(
        []
    );

    const client = useApolloClient();

    const [schema, setSchema] = useState<BulkSchema>();

    const resetStates = () => {
        setPage(0);
        setPageSize(20);
        setSuccess([]);
        setFailed([]);
        setIsLoading(false);
        setBulkEditEntries([]);
        setSchema(undefined);
        setError(null);
    };

    useEffect(() => {
        if (props.bulkEditFile) {
            const loadFile = async (file: File) => {
                resetStates();
                setIsLoading(true);

                try {
                    const { jsonData, columnNames } = await parseFile(file);

                    const parsedJsonArray: any[] = Array.isArray(jsonData)
                        ? jsonData
                        : [];

                    if (parsedJsonArray.length === 0) {
                        setError('No data found in the file.');
                        return;
                    }

                    let nextSchema: BulkSchema;
                    try {
                        nextSchema = selectSchemaByColumns(columnNames);
                        setSchema(nextSchema);
                    } catch (schemaError: any) {
                        setError(
                            schemaError?.message ||
                                'Invalid file format. Please check the file format and try again.'
                        );
                        return;
                    }

                    const mappedEntries = await nextSchema.toEntries(
                        client,
                        parsedJsonArray
                    );

                    setBulkEditEntries(mappedEntries);
                } catch (error: any) {
                    setError(error?.message || 'Error loading file.');
                } finally {
                    setIsLoading(false);
                }
            };

            void loadFile(props.bulkEditFile);
        }
    }, [props.bulkEditFile, client]);

    function onSuccess(entry: BulkEditEntryBase) {
        setSuccess(prev => [...prev, entry]);
    }

    function onFail(
        entry: BulkEditEntryBase,
        error: any,
        message: string | null
    ) {
        setFailed(prev => [...prev, { entry, error, message }]);
    }

    function applyBulkUpdate() {
        setSuccess([]);
        setFailed([]);
        schema!.apply(client, bulkEditEntries, onSuccess, onFail);
    }

    function renderSectionContent() {
        if (error) {
            return <Alert variant={'error'} text={error} />;
        }
        if (!props.bulkEditFile) {
            return <EntityBulkEditSupportedUpdateSchemas />;
        }

        return (
            <>
                {bulkEditEntries && bulkEditEntries.length > 0 && (
                    <div>
                        <EntityBulkEditProcessingStatus
                            success={success}
                            failed={failed}
                            all={bulkEditEntries}
                        />
                    </div>
                )}
                {schema && (
                    <>
                        <EntityBulkEditTemplateDownload schema={schema} />
                        <div className="EntityBulkEditFileInfo-table">
                            <EntityBulkEditTable
                                bulkEditEntriesList={bulkEditEntries}
                                columns={schema.columns}
                                entityName={schema.displayName}
                                isLoading={isLoading}
                                hasFilterApplied={false}
                                onClearFilters={() => {}}
                                page={page}
                                setPage={setPage}
                                pageSize={pageSize}
                                setPageSize={setPageSize}
                            />
                        </div>

                        <EntityBulkEditApplyButton
                            onApply={applyBulkUpdate}
                            isLoading={isLoading}
                        />
                    </>
                )}
            </>
        );
    }

    if (!props.bulkEditFile) {
        return <EntityBulkEditSupportedUpdateSchemas />;
    }

    return (
        <Section>
            <Section.Body testId={'entityBulkEditFileInfoBody'}>
                {renderSectionContent()}
            </Section.Body>
        </Section>
    );
};

export default EntityBulkEditFileInfo;
