import React, { useRef, useState, useEffect } from 'react';
import {
    Box,
    Typography,
    TextField,
    Button,
    Select,
    MenuItem,
    Snackbar,
    FormControl,
    InputLabel,
    IconButton,
    Tooltip,
    Alert,
} from '@mui/material';

import QRCode from 'react-qr-code';
import {
    Dewar,
    DewarType,
    DewarSerialNumber,
    ContactPerson,
    Address,
    ContactsService,
    AddressesService,
    DewarsService,
    ShipmentsService,
} from '../../openapi';
import Unipuck from '../components/Unipuck';
import { saveAs } from 'file-saver';
import DownloadIcon from '@mui/icons-material/Download';

interface DewarDetailsProps {
    dewar: Dewar;
    trackingNumber: string;
    setTrackingNumber: (trackingNumber: string) => void;
    initialContactPersons?: ContactPerson[];
    initialReturnAddresses?: Address[];
    defaultContactPerson?: ContactPerson;
    defaultReturnAddress?: Address;
    shipmentId: number;
}

interface NewContactPerson {
    id: number;
    firstName: string;
    lastName: string;
    phone_number: string;
    email: string;
}

interface NewReturnAddress {
    id: number;
    street: string;
    city: string;
    zipcode: string;
    country: string;
}

const DewarDetails: React.FC<DewarDetailsProps> = ({
                                                       dewar,
                                                       trackingNumber,
                                                       setTrackingNumber,
                                                       initialContactPersons = [],
                                                       initialReturnAddresses = [],
                                                       defaultContactPerson,
                                                       defaultReturnAddress,
                                                       shipmentId,
                                                   }) => {
    const [localTrackingNumber, setLocalTrackingNumber] = useState(trackingNumber);
    const [contactPersons, setContactPersons] = useState(initialContactPersons);
    const [returnAddresses, setReturnAddresses] = useState(initialReturnAddresses);
    const [selectedContactPerson, setSelectedContactPerson] = useState<string>('');
    const [selectedReturnAddress, setSelectedReturnAddress] = useState<string>('');
    const [isCreatingContactPerson, setIsCreatingContactPerson] = useState(false);
    const [isCreatingReturnAddress, setIsCreatingReturnAddress] = useState(false);
    const [puckStatuses, setPuckStatuses] = useState<string[][]>([]);
    const [newContactPerson, setNewContactPerson] = useState<NewContactPerson>({
        id: 0,
        firstName: '',
        lastName: '',
        phone_number: '',
        email: '',
    });
    const [newReturnAddress, setNewReturnAddress] = useState<NewReturnAddress>({
        id: 0,
        street: '',
        city: '',
        zipcode: '',
        country: '',
    });
    const [changesMade, setChangesMade] = useState(false);
    const [feedbackMessage, setFeedbackMessage] = useState<string>('');
    const [openSnackbar, setOpenSnackbar] = useState<boolean>(false);
    const [newDewarType, setNewDewarType] = useState<string>('');
    const [newDewarSerialNumber, setNewDewarSerialNumber] = useState<string>('');
    const [selectedDewarType, setSelectedDewarType] = useState<string>(dewar.dewar_type_id?.toString() || '');
    const [knownDewarTypes, setKnownDewarTypes] = useState<DewarType[]>([]);
    const [knownSerialNumbers, setKnownSerialNumbers] = useState<DewarSerialNumber[]>([]);
    const [selectedSerialNumber, setSelectedSerialNumber] = useState<string>('');
    const [isQRCodeGenerated, setIsQRCodeGenerated] = useState(false);
    const [qrCodeValue, setQrCodeValue] = useState(dewar.unique_id || '');
    const qrCodeRef = useRef<HTMLCanvasElement>(null); //

    useEffect(() => {
        const fetchDewarTypes = async () => {
            try {
                const response = await DewarsService.getDewarTypesDewarsDewarTypesGet();
                setKnownDewarTypes(response ?? []);
            } catch (error) {
                setFeedbackMessage('Failed to fetch dewar types.');
                setOpenSnackbar(true);
                console.error('Error fetching dewar types:', error);
            }
        };
        fetchDewarTypes();
    }, []);

    // Fetch known serial numbers
    useEffect(() => {
        const fetchSerialNumbers = async () => {
            try {
                const response = await DewarsService.getAllSerialNumbersDewarsDewarSerialNumbersGet();
                setKnownSerialNumbers(response ?? []);
            } catch (error) {
                setFeedbackMessage('Failed to fetch serial numbers.');
                setOpenSnackbar(true);
                console.error('Error fetching serial numbers:', error);
            }
        };
        fetchSerialNumbers();
    }, []);

    useEffect(() => {
        setLocalTrackingNumber(dewar.tracking_number || '');

        const setInitialContactPerson = () => {
            setSelectedContactPerson(
                dewar.contact_person?.id?.toString() || defaultContactPerson?.id?.toString() || ''
            );
        };

        const setInitialReturnAddress = () => {
            setSelectedReturnAddress(
                dewar.return_address?.id?.toString() || defaultReturnAddress?.id?.toString() || ''
            );
        };

        setInitialContactPerson();
        setInitialReturnAddress();

        if (dewar.dewar_type_id) {
            setSelectedDewarType(dewar.dewar_type_id.toString());
        }
        if (dewar.dewar_serial_number_id) {
            setSelectedSerialNumber(dewar.dewar_serial_number_id.toString());
        }
    }, [dewar, defaultContactPerson, defaultReturnAddress]);

    useEffect(() => {
        const getContacts = async () => {
            try {
                const c = await ContactsService.getContactsContactsGet();
                setContactPersons(c);
            } catch {
                setFeedbackMessage('Failed to load contact persons. Please try again later.');
                setOpenSnackbar(true);
            }
        };

        const getReturnAddresses = async () => {
            try {
                const a = await AddressesService.getReturnAddressesAddressesGet();
                setReturnAddresses(a);
            } catch {
                setFeedbackMessage('Failed to load return addresses. Please try again later.');
                setOpenSnackbar(true);
            }
        };

        getContacts();
        getReturnAddresses();
    }, []);

    useEffect(() => {
        const fetchSamples = async () => {
            if (dewar.id) {
                try {
                    const fetchedSamples = await ShipmentsService.getSamplesInDewarShipmentsShipmentsShipmentIdDewarsDewarIdSamplesGet(
                        shipmentId,
                        dewar.id
                    );

                    const updatedPuckStatuses = (dewar.pucks ?? []).map((puck) => {
                        const puckSamples = fetchedSamples.filter((sample) => sample.puck_id === puck.id);

                        const statusArray = Array(16).fill('empty');

                        puckSamples.forEach((sample) => {
                            if (sample.position >= 1 && sample.position <= 16) {
                                statusArray[sample.position - 1] = 'filled';
                            }
                        });

                        return statusArray;
                    });

                    setPuckStatuses(updatedPuckStatuses);
                } catch (error) {
                    console.error('Error fetching samples:', error);
                }
            }
        };

        fetchSamples();
    }, [dewar, shipmentId]);

    useEffect(() => {
        setSelectedDewarType(
            knownDewarTypes.find((type) => type.id === dewar.dewar_type_id)?.id.toString() || ''
        );
    }, [knownDewarTypes, dewar.dewar_type_id]);

    useEffect(() => {
        setSelectedSerialNumber(
            knownSerialNumbers.find((sn) => sn.id === dewar.dewar_serial_number_id)?.id.toString() || ''
        );
    }, [knownSerialNumbers, dewar.dewar_serial_number_id]);

    const validateEmail = (email: string) => /\S+@\S+\.\S+/.test(email);
    const validatePhoneNumber = (phone: string) => /^\+?[1-9]\d{1,14}$/.test(phone);
    const validateZipCode = (zipcode: string) => /^\d{4,5}(?:[-\s]\d{4})?$/.test(zipcode);

    if (!dewar) return <Typography>No dewar selected.</Typography>;

    const handleSaveNewDewarTypeAndSerialNumber = async () => {
        if (newDewarType) {
            try {
                const typeResponse = await DewarsService.createDewarTypeDewarsDewarTypesPost({ dewar_type: newDewarType });
                const serialResponse = await DewarsService.createDewarSerialNumberDewarsDewarSerialNumbersPost({
                    serial_number: newDewarSerialNumber,
                    dewar_type_id: typeResponse.id,
                });
                setKnownDewarTypes([...knownDewarTypes, typeResponse]);
                setKnownSerialNumbers([...knownSerialNumbers, serialResponse]);
                setSelectedDewarType(typeResponse.id.toString());
                setSelectedSerialNumber(serialResponse.serial_number);
                setNewDewarType('');
                setNewDewarSerialNumber('');
                setChangesMade(true);
            } catch (error) {
                setFeedbackMessage('Failed to save new dewar type and serial number.');
                setOpenSnackbar(true);
            }
        } else if (newDewarSerialNumber && selectedDewarType) {
            try {
                const response = await DewarsService.createDewarSerialNumberDewarsDewarSerialNumbersPost({
                    serial_number: newDewarSerialNumber,
                    dewar_type_id: parseInt(selectedDewarType, 10),
                });
                setKnownSerialNumbers([...knownSerialNumbers, response]);
                setSelectedSerialNumber(response.serial_number);
                setNewDewarSerialNumber('');
                setChangesMade(true);
            } catch (error) {
                setFeedbackMessage('Failed to save new serial number.');
                setOpenSnackbar(true);
            }
        }
    };

    const handleAddContact = async () => {
        if (!validateEmail(newContactPerson.email) || !validatePhoneNumber(newContactPerson.phone_number) || !newContactPerson.firstName || !newContactPerson.lastName) {
            setFeedbackMessage('Please fill in all new contact person fields correctly.');
            setOpenSnackbar(true);
            return;
        }

        const payload = {
            firstname: newContactPerson.firstName,
            lastname: newContactPerson.lastName,
            phone_number: newContactPerson.phone_number,
            email: newContactPerson.email,
        };

        try {
            const c = await ContactsService.createContactContactsPost(payload);
            setContactPersons([...contactPersons, c]);
            setFeedbackMessage('Contact person added successfully.');
            setNewContactPerson({ id: 0, firstName: '', lastName: '', phone_number: '', email: '' });
            setSelectedContactPerson(c.id?.toString() || '');
        } catch {
            setFeedbackMessage('Failed to create a new contact person. Please try again later.');
        }

        setOpenSnackbar(true);
        setIsCreatingContactPerson(false);
        setChangesMade(true);
    };

    const handleAddAddress = async () => {
        if (!validateZipCode(newReturnAddress.zipcode) || !newReturnAddress.street || !newReturnAddress.city || !newReturnAddress.country) {
            setFeedbackMessage('Please fill in all new return address fields correctly.');
            setOpenSnackbar(true);
            return;
        }

        const payload = {
            street: newReturnAddress.street.trim(),
            city: newReturnAddress.city.trim(),
            zipcode: newReturnAddress.zipcode.trim(),
            country: newReturnAddress.country.trim(),
        };

        try {
            const a = await AddressesService.createReturnAddressAddressesPost(payload);
            setReturnAddresses([...returnAddresses, a]);
            setFeedbackMessage('Return address added successfully.');
            setNewReturnAddress({
                id: 0,
                street: '',
                city: '',
                zipcode: '',
                country: '',
            });
            setSelectedReturnAddress(a.id?.toString() || '');
        } catch {
            setFeedbackMessage('Failed to create a new return address. Please try again later.');
        }

        setOpenSnackbar(true);
        setIsCreatingReturnAddress(false);
        setChangesMade(true);
    };

    const handleSaveChanges = async () => {
        const formatDate = (dateString: string | null) => {
            if (!dateString) return null;
            const date = new Date(dateString);
            if (isNaN(date.getTime())) return null;
            return date.toISOString().split('T')[0];
        };

        if (!selectedContactPerson || !selectedReturnAddress) {
            setFeedbackMessage('Please ensure all required fields are filled.');
            setOpenSnackbar(true);
            return;
        }

        const dewarId = dewar.id;

        if (!dewarId) {
            setFeedbackMessage('Invalid Dewar ID. Please ensure Dewar ID is provided.');
            setOpenSnackbar(true);
            return;
        }

        try {
            const payload = {
                dewar_name: dewar.dewar_name,
                dewar_type_id: parseInt(selectedDewarType, 10),
                dewar_serial_number_id: parseInt(selectedSerialNumber, 10),
                tracking_number: localTrackingNumber,
                number_of_pucks: dewar.number_of_pucks,
                number_of_samples: dewar.number_of_samples,
                status: dewar.status,
                ready_date: formatDate(dewar.ready_date),
                shipping_date: formatDate(dewar.shipping_date),
                arrival_date: dewar.arrival_date,
                returning_date: dewar.returning_date,
                return_address_id: parseInt(selectedReturnAddress ?? '', 10),
                contact_person_id: parseInt(selectedContactPerson ?? '', 10),
            };

            await DewarsService.updateDewarDewarsDewarIdPut(dewarId, payload);
            setFeedbackMessage('Changes saved successfully.');
            setChangesMade(false);
        } catch (error) {
            setFeedbackMessage('Failed to save changes. Please try again later.');
            setOpenSnackbar(true);
        }
    };

    const handleSerialNumberChange = (value: string) => {
        setSelectedSerialNumber(value);
        const serialNumber = knownSerialNumbers.find((sn) => sn.id.toString() === value);
        if (serialNumber) {
            setSelectedDewarType(serialNumber.dewar_type_id.toString());
        }
        setChangesMade(true);
    };

    const handleGenerateQRCode = async () => {
        if (!dewar) return;

        try {
            const response = await DewarsService.generateDewarQrcodeDewarsDewarIdGenerateQrcodePost(dewar.id);
            const newQrCodeValue = response.unique_id;
            setQrCodeValue(newQrCodeValue);
            setIsQRCodeGenerated(true);
            setFeedbackMessage("QR Code generated successfully");
            setOpenSnackbar(true);
        } catch (error) {
            console.error("Failed to generate QR code:", error);
            setFeedbackMessage("QR Code generation failed");
            setOpenSnackbar(true);
        }
    };


    const handleDownloadLabel = async () => {
        if (!dewar) return;

        try {
            const response = await DewarsService.downloadDewarLabelDewarsDewarIdDownloadLabelGet(dewar.id);

            // The response object might need parsing
            const blob = new Blob([response as any], { type: 'application/pdf' });
            const url = window.URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href = url;
            link.setAttribute('download', `dewar_label_${dewar.id}.pdf`);
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);

            setFeedbackMessage("Label downloaded successfully");
            setOpenSnackbar(true);
        } catch (error) {
            console.error("Failed to download label:", error);
            setFeedbackMessage("Label download failed");
            setOpenSnackbar(true);
        }
    };

    return (
        <Box sx={{ marginTop: 2 }}>
            <Typography variant="h6">Selected Dewar: {dewar.dewar_name}</Typography>
            <TextField
                label="Tracking Number"
                value={localTrackingNumber}
                onChange={(e) => {
                    setLocalTrackingNumber(e.target.value);
                    setTrackingNumber(e.target.value);
                    setChangesMade(true);
                }}
                variant="outlined"
                sx={{ width: '300px', marginBottom: 2 }}
            />
            <FormControl variant="outlined" sx={{ width: '300px', marginBottom: 2 }}>
                <InputLabel id="dewar-serial-number-label">Dewar Serial Number</InputLabel>
                <Select
                    labelId="dewar-serial-number-label"
                    label="Dewar Serial Number"
                    value={selectedSerialNumber}
                    onChange={(e) => handleSerialNumberChange(e.target.value as string)}
                    displayEmpty
                >
                    {knownSerialNumbers.map((sn) => (
                        <MenuItem key={sn.id} value={sn.id.toString()}>
                            {sn.serial_number}
                        </MenuItem>
                    ))}
                    <MenuItem value="add">Add New Serial Number</MenuItem>
                </Select>
                {selectedSerialNumber === 'add' && (
                    <Box>
                        <FormControl variant="outlined" sx={{ width: '300px', marginBottom: 2 }}>
                            <InputLabel id="dewar-type-label">Dewar Type</InputLabel>
                            <Select
                                labelId="dewar-type-label"
                                label="Dewar Type"
                                value={selectedDewarType}
                                onChange={(e) => {
                                    const value = e.target.value as string;
                                    setSelectedDewarType(value);
                                    setChangesMade(true);
                                }}
                                displayEmpty
                            >
                                {knownDewarTypes.map((type) => (
                                    <MenuItem key={type.id} value={type.id.toString()}>
                                        {type.dewar_type}
                                    </MenuItem>
                                ))}
                                <MenuItem value="add">Add New Dewar Type</MenuItem>
                            </Select>
                            {selectedDewarType === 'add' && (
                                <Box>
                                    <TextField
                                        label="Add New Dewar Type"
                                        value={newDewarType}
                                        onChange={(e) => setNewDewarType(e.target.value)}
                                        variant="outlined"
                                        sx={{ width: '300px', marginBottom: 2 }}
                                    />
                                </Box>
                            )}
                        </FormControl>
                        <TextField
                            label="Add New Serial Number"
                            value={newDewarSerialNumber}
                            onChange={(e) => setNewDewarSerialNumber(e.target.value)}
                            variant="outlined"
                            sx={{ width: '300px', marginBottom: 2 }}
                        />
                        <Button onClick={handleSaveNewDewarTypeAndSerialNumber} variant="contained">
                            Save Dewar Type and Serial Number
                        </Button>
                    </Box>
                )}
            </FormControl>

            <Box sx={{ textAlign: 'center', marginBottom: 2 }}>
                {qrCodeValue ? (
                    <Box>
                        <QRCode id="qrCodeCanvas" value={qrCodeValue} size={150} />
                        <Box sx={{ display: 'flex', alignItems: 'center', marginTop: 1 }}>
                            <Tooltip title="Download Label">
                                <IconButton onClick={handleDownloadLabel} sx={{ transform: 'scale(1.5)', margin: 1 }}>
                                    <DownloadIcon />
                                </IconButton>
                            </Tooltip>
                            <Typography variant="body2">Label is ready for download</Typography>
                        </Box>
                    </Box>
                ) : (
                    <Typography>No QR code available</Typography>
                )}
                <Button
                    variant="contained"
                    sx={{ marginTop: 1 }}
                    onClick={handleGenerateQRCode}
                >
                    Generate QR Code
                </Button>
            </Box>

            <Box sx={{ marginTop: 2 }}>
                <Typography variant="body1">Number of Pucks: {dewar.number_of_pucks}</Typography>
                {(dewar.pucks ?? []).length > 0 ? (
                    <Unipuck pucks={(dewar.pucks ?? []).length} samples={puckStatuses} />
                ) : (
                    <Typography>No pucks attached to the dewar.</Typography>
                )}
                <Typography variant="body1">Number of Samples: {dewar.number_of_samples}</Typography>
            </Box>

            <Typography variant="body1">Current Contact Person:</Typography>
            <Select
                value={selectedContactPerson}
                onChange={(e) => {
                    const value = e.target.value;
                    setSelectedContactPerson(value);
                    setIsCreatingContactPerson(value === 'add');
                    setChangesMade(true);
                }}
                displayEmpty
                sx={{ width: '300px', marginBottom: 2 }}
            >
                {contactPersons.map((person) => (
                    <MenuItem key={person.id} value={person.id?.toString()}>
                        {person.firstname} {person.lastname}
                    </MenuItem>
                ))}
                <MenuItem value="add">Add New Contact Person</MenuItem>
            </Select>
            {isCreatingContactPerson && (
                <Box sx={{ marginBottom: 2 }}>
                    <TextField
                        label="First Name"
                        value={newContactPerson.firstName}
                        onChange={(e) =>
                            setNewContactPerson((prev) => ({
                                ...prev,
                                firstName: e.target.value,
                            }))
                        }
                        variant="outlined"
                        sx={{ width: '300px', marginBottom: 2 }}
                    />
                    <TextField
                        label="Last Name"
                        value={newContactPerson.lastName}
                        onChange={(e) =>
                            setNewContactPerson((prev) => ({
                                ...prev,
                                lastName: e.target.value,
                            }))
                        }
                        variant="outlined"
                        sx={{ width: '300px', marginBottom: 2 }}
                    />
                    <TextField
                        label="Phone Number"
                        value={newContactPerson.phone_number}
                        onChange={(e) =>
                            setNewContactPerson((prev) => ({
                                ...prev,
                                phone_number: e.target.value,
                            }))
                        }
                        variant="outlined"
                        sx={{ width: '300px', marginBottom: 2 }}
                    />
                    <TextField
                        label="Email"
                        value={newContactPerson.email}
                        onChange={(e) =>
                            setNewContactPerson((prev) => ({
                                ...prev,
                                email: e.target.value,
                            }))
                        }
                        variant="outlined"
                        sx={{ width: '300px', marginBottom: 2 }}
                    />
                    <Button onClick={handleAddContact} variant="contained">
                        Save New Contact Person
                    </Button>
                </Box>
            )}

            <Typography variant="body1">Current Return Address:</Typography>
            <Select
                value={selectedReturnAddress}
                onChange={(e) => {
                    const value = e.target.value;
                    setSelectedReturnAddress(value);
                    setIsCreatingReturnAddress(value === 'add');
                    setChangesMade(true);
                }}
                displayEmpty
                sx={{ width: '300px', marginBottom: 2 }}
            >
                {returnAddresses.map((address) => (
                    <MenuItem key={address.id} value={address.id?.toString()}>
                        {address.street}, {address.city}, {address.zipcode}, {address.country}
                    </MenuItem>
                ))}
                <MenuItem value="add">Add New Return Address</MenuItem>
            </Select>
            {isCreatingReturnAddress && (
                <Box sx={{ marginBottom: 2 }}>
                    <TextField
                        label="Street"
                        value={newReturnAddress.street}
                        onChange={(e) =>
                            setNewReturnAddress((prev) => ({
                                ...prev,
                                street: e.target.value,
                            }))
                        }
                        variant="outlined"
                        sx={{ width: '300px', marginBottom: 2 }}
                    />
                    <TextField
                        label="City"
                        value={newReturnAddress.city}
                        onChange={(e) =>
                            setNewReturnAddress((prev) => ({
                                ...prev,
                                city: e.target.value,
                            }))
                        }
                        variant="outlined"
                        sx={{ width: '300px', marginBottom: 2 }}
                    />
                    <TextField
                        label="Zip Code"
                        value={newReturnAddress.zipcode}
                        onChange={(e) =>
                            setNewReturnAddress((prev) => ({
                                ...prev,
                                zipcode: e.target.value,
                            }))
                        }
                        variant="outlined"
                        sx={{ width: '300px', marginBottom: 2 }}
                    />
                    <TextField
                        label="Country"
                        value={newReturnAddress.country}
                        onChange={(e) =>
                            setNewReturnAddress((prev) => ({
                                ...prev,
                                country: e.target.value,
                            }))
                        }
                        variant="outlined"
                        sx={{ width: '300px', marginBottom: 2 }}
                    />
                    <Button onClick={handleAddAddress} variant="contained">
                        Save New Return Address
                    </Button>
                </Box>
            )}

            <Box sx={{ marginTop: 2 }}>
                <Button
                    variant="contained"
                    color="primary"
                    onClick={handleSaveChanges}
                    disabled={!changesMade}
                >
                    Save Changes
                </Button>
            </Box>

            <Snackbar
                open={openSnackbar}
                autoHideDuration={6000}
                onClose={() => setOpenSnackbar(false)}
            >
                <Alert onClose={() => setOpenSnackbar(false)} severity="info" sx={{ width: '100%' }}>
                    {feedbackMessage}
                </Alert>
            </Snackbar>
        </Box>
    );
};

export default DewarDetails;