import React, { useState, useEffect } from 'react';
import {
    Table,
    TableBody,
    TableCell,
    TableContainer,
    TableHead,
    TableRow,
    Paper,
    Tooltip,
    TextField,
    Typography,
    Button,
    Box
} from '@mui/material';
import { SpreadsheetService, ShipmentsService, DewarsService, ApiError } from '../../openapi';
import * as ExcelJS from 'exceljs';
import { saveAs } from 'file-saver';

const SpreadsheetTable = ({
                              raw_data,
                              errors,
                              headers,
                              setRawData,
                              onCancel,
                              fileBlob,
                              selectedShipment
                          }) => {
    const [localErrors, setLocalErrors] = useState(errors || []);
    const [editingCell, setEditingCell] = useState({});
    const [nonEditableCells, setNonEditableCells] = useState(new Set());
    const [isSubmitting, setIsSubmitting] = useState(false);

    const initialNewDewarState = {
        number_of_pucks: 0,
        number_of_samples: 0,
        ready_date: null,
        shipping_date: null,
        arrival_date: null,
        returning_date: null,
        qrcode: 'N/A',
        contact_person_id: selectedShipment?.contact_person?.id,
        return_address_id: selectedShipment?.return_address?.id,
        dewar_name: '',
        tracking_number: 'UNKNOWN',
        status: 'In preparation',
        pucks: []
    };

    const [newDewar, setNewDewar] = useState(initialNewDewarState);

    useEffect(() => {
        setNewDewar((prev) => ({
            ...prev,
            contact_person_id: selectedShipment?.contact_person?.id,
            return_address_id: selectedShipment?.return_address?.id
        }));
    }, [selectedShipment]);

    const generateErrorMap = (errorsList) => {
        const errorMap = new Map();
        if (Array.isArray(errorsList)) {
            errorsList.forEach((error) => {
                const key = `${error.row}-${headers[error.cell]}`;
                errorMap.set(key, error.message);
            });
        }
        return errorMap;
    };

    const errorMap = generateErrorMap(localErrors);

    useEffect(() => {
        const initialNonEditableCells = new Set();
        raw_data.forEach((row, rowIndex) => {
            headers.forEach((_, colIndex) => {
                const key = `${row.row_num}-${headers[colIndex]}`;
                if (!errorMap.has(key)) {
                    initialNonEditableCells.add(`${rowIndex}-${colIndex}`);
                }
            });
        });
        setNonEditableCells(initialNonEditableCells);
    }, [raw_data, headers, errorMap]);

    const handleCellEdit = async (rowIndex, colIndex) => {
        const updatedRawData = [...raw_data];
        const columnName = headers[colIndex];
        const currentRow = updatedRawData[rowIndex];
        const newValue = editingCell[`${rowIndex}-${colIndex}`];

        if (newValue === undefined) return;

        if (!currentRow.data) {
            currentRow.data = [];
        }

        currentRow.data[colIndex] = newValue;

        setEditingCell((prev) => {
            const updated = { ...prev };
            delete updated[`${rowIndex}-${colIndex}`];
            return updated;
        });

        try {
            const response = await SpreadsheetService.validateCellValidateCellPost({
                row: currentRow.row_num,
                column: columnName,
                value: newValue
            });

            if (response.is_valid !== undefined) {
                if (response.is_valid) {
                    const updatedErrors = localErrors.filter(
                        (error) => !(error.row === currentRow.row_num && error.cell === colIndex)
                    );
                    setLocalErrors(updatedErrors);
                    setNonEditableCells((prev) => new Set([...prev, `${rowIndex}-${colIndex}`]));
                } else {
                    const updatedErrors = [
                        ...localErrors,
                        { row: currentRow.row_num, cell: colIndex, message: response.message || 'Invalid value.' }
                    ];
                    setLocalErrors(updatedErrors);
                }
            }
            setRawData(updatedRawData);
        } catch (error) {
            console.error('Validation failed:', error);
        }
    };

    const handleCellBlur = (rowIndex, colIndex) => {
        handleCellEdit(rowIndex, colIndex);
    };

    const allCellsValid = () => nonEditableCells.size === raw_data.length * headers.length;

    const fieldToCol = {
        'dewarname': 0,
        'puckname': 1,
        'pucktype': 2,
        // Add other fields as needed
    };

    const createDewarsFromSheet = async (data, contactPerson, returnAddress) => {
        if (!contactPerson?.id || !returnAddress?.id) {
            console.error('contact_person_id or return_address_id is missing');
            return null;
        }

        const dewars = new Map();

        const dewarNameIdx = fieldToCol['dewarname'];
        const puckNameIdx = fieldToCol['puckname'];
        const puckTypeIdx = fieldToCol['pucktype'];

        let puckPositionInDewar = 1;

        for (const row of data) {
            if (!row.data) {
                console.error(`Row data is missing`);
                continue;
            }

            const dewarName = typeof row.data[dewarNameIdx] === 'string' ? row.data[dewarNameIdx].trim() : null;
            const puckName = typeof row.data[puckNameIdx] === 'string' ? row.data[puckNameIdx].trim() : null;
            const puckType = typeof row.data[puckTypeIdx] === 'string' ? row.data[puckTypeIdx] : 'Unipuck';

            console.log(`Processing Dewar: ${dewarName}, Puck: ${puckName}, Type: ${puckType}`);

            if (dewarName) {
                let dewar;
                if (!dewars.has(dewarName)) {
                    dewar = {
                        ...initialNewDewarState,
                        dewar_name: dewarName,
                        contact_person_id: contactPerson.id,
                        return_address_id: returnAddress.id,
                        pucks: []
                    };
                    dewars.set(dewarName, dewar);
                    puckPositionInDewar = 1;
                    console.log(`Created new dewar: ${dewarName}`);
                } else {
                    dewar = dewars.get(dewarName);
                    puckPositionInDewar++;
                    console.log(`Found existing dewar: ${dewarName}`);
                }

                const puck = {
                    puck_name: puckName || 'test', // Fixed puck name
                    puck_type: puckType || 'Unipuck', // Fixed puck type
                    puck_position_in_dewar: puckPositionInDewar
                };
                dewar.pucks.push(puck);

                console.log(`Added puck: ${JSON.stringify(puck)}`);
            } else {
                console.error('Dewar name is missing in the row');
            }
        }

        const dewarsArray = Array.from(dewars.values());
        for (const dewar of dewarsArray) {
            try {
                // Call to create the dewar
                const createdDewar = await DewarsService.createDewarDewarsPost(dewar);
                console.log(`Created dewar: ${createdDewar.id}`);

                // Add dewar to the shipment if created successfully
                if (createdDewar && selectedShipment) {
                    await ShipmentsService.addDewarToShipmentShipmentsShipmentIdAddDewarPost(
                        selectedShipment.id,
                        createdDewar.id
                    );
                    console.log(`Added dewar to shipment: ${createdDewar.id}`);
                }
            } catch (error) {
                console.error(`Error adding dewar`, error);
                if (error instanceof ApiError && error.body) {
                    console.error('Validation errors:', error.body.detail);
                } else {
                    console.error('Unexpected error:', error);
                }
            }
        }

        return dewarsArray;
    };

    const handleSubmit = async () => {
        if (isSubmitting) return;
        if (!headers || headers.length === 0) {
            console.error('Cannot submit, headers are not defined or empty');
            return;
        }

        if (allCellsValid()) {
            setIsSubmitting(true);
            console.log('All data is valid. Proceeding with submission...');

            const processedDewars = await createDewarsFromSheet(
                raw_data,
                selectedShipment?.contact_person,
                selectedShipment?.return_address
            );

            if (processedDewars && processedDewars.length > 0) {
                console.log('Dewars processed successfully.');
            } else {
                console.error('No valid dewars were created.');
            }

            setIsSubmitting(false);
        } else {
            console.log('There are validation errors in the dataset. Please correct them before submission.');
        }
    };

    const downloadCorrectedSpreadsheet = async () => {
        const workbook = new ExcelJS.Workbook();
        await workbook.xlsx.load(fileBlob);
        const worksheet = workbook.getWorksheet(1);

        raw_data.forEach((row, rowIndex) => {
            row.data.forEach((value, colIndex) => {
                worksheet.getRow(row.row_num).getCell(colIndex + 1).value = value;
            });
        });

        const buffer = await workbook.xlsx.writeBuffer();
        const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });

        saveAs(blob, 'corrected_data.xlsx');
    };

    useEffect(() => {
        console.log('Raw data:', raw_data);
        console.log('Errors:', localErrors);
        console.log('Headers:', headers);
    }, [raw_data, localErrors, headers]);

    if (!raw_data || !headers) {
        return <div>Loading...</div>;
    }

    return (
        <TableContainer component={Paper}>
            <Table>
                <TableHead>
                    <TableRow>
                        {headers.map((header, index) => (
                            <TableCell key={index} align="center">
                                <Typography variant="body2">{header}</Typography>
                            </TableCell>
                        ))}
                    </TableRow>
                </TableHead>
                <Box display="flex" justifyContent="space-between" mt={2}>
                    <Button variant="contained" color="secondary" onClick={onCancel}>
                        Cancel
                    </Button>
                    <Button variant="contained" color="primary" onClick={handleSubmit} disabled={!allCellsValid() || isSubmitting}>
                        Submit
                    </Button>
                    <Button variant="contained" onClick={downloadCorrectedSpreadsheet} disabled={!allCellsValid()}>
                        Download Corrected Spreadsheet
                    </Button>
                </Box>
                <TableBody>
                    {raw_data.map((row, rowIndex) => (
                        <TableRow key={rowIndex}>
                            {headers.map((header, colIndex) => {
                                const key = `${row.row_num}-${header}`;
                                const errorMessage = errorMap.get(key);
                                const isInvalid = !!errorMessage;
                                const cellValue = (row.data && row.data[colIndex]) || "";
                                const editingValue = editingCell[`${rowIndex}-${colIndex}`];
                                const isReadonly = !isInvalid;

                                return (
                                    <TableCell key={colIndex} align="center">
                                        <Tooltip title={errorMessage || ""} arrow disableHoverListener={!isInvalid}>
                                            <TextField
                                                value={editingValue !== undefined ? editingValue : cellValue}
                                                onChange={(e) => setEditingCell({ ...editingCell, [`${rowIndex}-${colIndex}`]: e.target.value })}
                                                onKeyDown={(e) => {
                                                    if (e.key === "Enter") {
                                                        handleCellEdit(rowIndex, colIndex);
                                                    }
                                                }}
                                                onBlur={() => handleCellBlur(rowIndex, colIndex)}
                                                error={isInvalid}
                                                fullWidth
                                                variant="outlined"
                                                size="small"
                                                disabled={isReadonly}
                                            />
                                        </Tooltip>
                                    </TableCell>
                                );
                            })}
                        </TableRow>
                    ))}
                </TableBody>
            </Table>
        </TableContainer>
    );
};

export default SpreadsheetTable;