import * as React from 'react';
import Fuse from 'fuse.js';
import {
    Box, Button, TextField, Typography, Select, MenuItem, Stack, FormControl, InputLabel
} from '@mui/material';
import { SelectChangeEvent } from '@mui/material';
import { SxProps } from '@mui/system';
import {
    ContactCreate, Contact, Address, AddressCreate, Proposal, ContactsService, AddressesService, ProposalsService,
    OpenAPI, ShipmentCreate, ShipmentsService
} from '../../openapi';
import { useEffect } from 'react';
import { CountryList } from './CountryList'; // Import the list of countries

const MAX_COMMENTS_LENGTH = 200;

interface ShipmentFormProps {
    activePgroup: string;
    sx?: SxProps;
    onCancel: () => void;
    refreshShipments: () => void;
}

// Set up Fuse.js for fuzzy searching
const fuse = new Fuse(CountryList, {
    threshold: 0.3,
    includeScore: true,
});

const token = localStorage.getItem('token');

if (token) {
    OpenAPI.TOKEN = token; // Ensure OpenAPI client uses this token
}

const ShipmentForm: React.FC<ShipmentFormProps> = ({
                                                       activePgroup,
                                                       sx = {},
                                                       onCancel,
                                                       refreshShipments }) => {
    const [countrySuggestions, setCountrySuggestions] = React.useState<string[]>([]);
    const [contacts, setContacts] = React.useState<Contact[]>([]);
    const [returnAddresses, setReturnAddresses] = React.useState<Address[]>([]);
    const [proposals, setProposals] = React.useState<Proposal[]>([]);
    const [isCreatingContact, setIsCreatingContact] = React.useState(false);
    const [isCreatingReturnAddress, setIsCreatingReturnAddress] = React.useState(false);
    const [newContact, setNewContact] = React.useState<ContactCreate>({
        pgroups:'', firstname: '', lastname: '', phone_number: '', email: ''
    });
    const [newReturnAddress, setNewReturnAddress] = React.useState<Omit<Address, 'id'>>({
        pgroups:'', house_number: '', street: '', city: '', state: '', zipcode: '', country: ''
    });
    const [newShipment, setNewShipment] = React.useState<Partial<ShipmentCreate>>({
        shipment_name: '', shipment_status: 'In preparation', comments: ''
    });
    const [selectedContactId, setSelectedContactId] = React.useState<number | null>(null);
    const [selectedReturnAddressId, setSelectedReturnAddressId] = React.useState<number | null>(null);
    const [selectedProposalId, setSelectedProposalId] = React.useState<number | null>(null);
    const [errorMessage, setErrorMessage] = React.useState<string | null>(null);

    useEffect(() => {
        // Detect the current environment
        const mode = import.meta.env.MODE;

        // Consistent dynamic `OpenAPI.BASE` resolution
        OpenAPI.BASE =
            mode === 'test'
                ? import.meta.env.VITE_OPENAPI_BASE_TEST
                : mode === 'prod'
                ? import.meta.env.VITE_OPENAPI_BASE_PROD
                : import.meta.env.VITE_OPENAPI_BASE_DEV;

        // Log warning if `OpenAPI.BASE` is unresolved
        if (!OpenAPI.BASE) {
            console.error('OpenAPI.BASE is not set. Falling back to a default value.');
            OpenAPI.BASE = 'https://default-url.com'; // Define fallback
        }

        console.log('Environment Mode:', mode);
        console.log('Resolved OpenAPI.BASE:', OpenAPI.BASE);

        // Fetch necessary data
        const getContacts = async () => {
            if (!activePgroup) {
                console.error("Active pgroup is missing.");
                setErrorMessage("Active pgroup is missing. Unable to load contacts.");
                return;
            }
            try {
                const fetchedContacts: Contact[] =
                    await ContactsService.getContactsProtectedContactsGet(activePgroup);
                setContacts(fetchedContacts);
            } catch {
                setErrorMessage('Failed to load contact s.');
            }
        };

        const getAddresses = async () => {
            if (!activePgroup) {
                console.error("Active pgroup is missing.");
                setErrorMessage("Active pgroup is missing. Unable to load addresses.");
                return;
            }

            try {
                // Pass activePgroup directly as a string (not as an object)
                const fetchedAddresses: Address[] =
                    await AddressesService.getReturnAddressesProtectedAddressesGet(activePgroup);

                setReturnAddresses(fetchedAddresses);
            } catch (error) {
                console.error("Error fetching addresses:", error);

                // Extract and log meaningful information from OpenAPI errors (if available)
                setErrorMessage("Failed to load return addresses due to API error.");
            }
        };

        const getProposals = async () => {
            try {
                const fetchedProposals: Proposal[] =
                    await ProposalsService.getProposalsProposalsGet();
                setProposals(fetchedProposals);
            } catch {
                setErrorMessage('Failed to load proposals.');
            }
        };

        getContacts();
        getAddresses();
        getProposals();
    }, [activePgroup]);

    const handleCountryInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        const value = event.target.value;

        setNewReturnAddress({ ...newReturnAddress, country: value });

        if (value) {
            const suggestions = fuse.search(value).map((result) => result.item);
            setCountrySuggestions(suggestions);
        } else {
            setCountrySuggestions([]);
        }
    };

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

    const isContactFormValid = () => {
        const { firstname, lastname, phone_number, email } = newContact;

        if (isCreatingContact) {
            if (!firstname || !lastname || !validateEmail(email) || !validatePhoneNumber(phone_number)) return false;
        }

        return true;
    };

    const isAddressFormValid = () => {
        const { street, city, zipcode, country } = newReturnAddress;

        if (isCreatingReturnAddress) {
            if (!street || !city || !validateZipCode(zipcode) || !country) return false;
        }

        return true;
    };

    const isFormValid = () => {
        const { shipment_name } = newShipment;

        if (!shipment_name) return false;
        if (!selectedContactId || !selectedReturnAddressId || !selectedProposalId) return false;

        if (isCreatingContact && !isContactFormValid()) return false;
        if (isCreatingReturnAddress && !isAddressFormValid()) return false;

        return true;
    };

    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const { name, value } = e.target;
        setNewShipment((prev) => ({ ...prev, [name]: value }));
    };

    const handleSaveShipment = async () => {
        if (!isFormValid()) {
            setErrorMessage('Please fill in all mandatory fields correctly.');
            return;
        }

        const payload: ShipmentCreate = {
            shipment_name: newShipment.shipment_name || '',
            shipment_date: new Date().toISOString().split('T')[0], // Remove if date is not required
            shipment_status: newShipment.shipment_status || 'In preparation',
            comments: newShipment.comments || '',
            contact_id: selectedContactId!,
            return_address_id: selectedReturnAddressId!,
            proposal_id: selectedProposalId!,
            dewars: newShipment.dewars || [],
            pgroups: activePgroup,
        };

        console.log('Shipment Payload being sent:', payload);

        try {
            await ShipmentsService.createShipmentProtectedShipmentsPost(payload);
            setErrorMessage(null);
            refreshShipments();
            onCancel();
        } catch (error) {
            console.error('Failed to save shipment:', error);
            setErrorMessage('Failed to save shipment. Please try again.');
        }
    };

    const handleContactChange = (event: SelectChangeEvent) => {
        const value = event.target.value;
        if (value === 'new') {
            setIsCreatingContact(true);
            setSelectedContactId(null);
        } else {
            setIsCreatingContact(false);
            setSelectedContactId(parseInt(value));
        }
    };

    const handleReturnAddressChange = (event: SelectChangeEvent) => {
        const value = event.target.value;
        if (value === 'new') {
            setIsCreatingReturnAddress(true);
            setSelectedReturnAddressId(null);
        } else {
            setIsCreatingReturnAddress(false);
            setSelectedReturnAddressId(parseInt(value));
        }
    };

    const handleProposalChange = (event: SelectChangeEvent) => {
        const value = event.target.value;
        setSelectedProposalId(parseInt(value));
    };

    const handleSaveNewContact = async () => {
        // Validate contact form fields
        if (!isContactFormValid(newContact)) {
            setErrorMessage('Please fill in all new contact person fields correctly.');
            return;
        }

        // Ensure activePgroup is available
        if (!activePgroup) {
            setErrorMessage('Active pgroup is missing. Please try again.');
            return;
        }

        // Construct the payload
        const payload: ContactCreate = {
            pgroups: activePgroup, // Ensure this value is available
            firstname: newContact.firstname.trim(),
            lastname: newContact.lastname.trim(),
            phone_number: newContact.phone_number.trim(),
            email: newContact.email.trim(),
        };

        console.log('Payload being sent:', JSON.stringify(payload, null, 2));

        try {
            // Call the API with the correctly constructed payload
            const newPerson: Contact = await ContactsService.createContactProtectedContactsPost(payload);

            // Update state on success
            setContacts([...contacts, newPerson]); // Add new contact to the list
            setErrorMessage(null); // Clear error messages
            setSelectedContactId(newPerson.id); // Optionally select the contact

            // Reset form inputs
            setNewContact({ pgroups: '', firstname: '', lastname: '', phone_number: '', email: '' });
            setIsCreatingContact(false);
        } catch (error) {
            console.error('Failed to create a new contact person:', error);

            // Handle detailed backend error messages if available
            if (error.response?.data?.detail) {
                setErrorMessage(`Error: ${error.response.data.detail}`);
            } else {
                setErrorMessage('Failed to create a new contact person. Please try again later.');
            }
        }
    };

    const handleSaveNewReturnAddress = async () => {
        // Validate address form data
        if (!validateZipCode(newReturnAddress.zipcode) || !newReturnAddress.street || !newReturnAddress.city || !newReturnAddress.country) {
            setErrorMessage('Please fill in all new return address fields correctly.');
            return;
        }

        // Ensure activePgroup is available
        if (!activePgroup) {
            setErrorMessage('Active pgroup is missing. Please try again.');
            return;
        }

        // Construct the payload
        const payload: AddressCreate = {
            pgroups: activePgroup, // Use the activePgroup prop directly
            house_number: newReturnAddress.house_number,
            street: newReturnAddress.street,
            city: newReturnAddress.city,
            state: newReturnAddress.state,
            zipcode: newReturnAddress.zipcode,
            country: newReturnAddress.country,
        };

        console.log('Return Address Payload being sent:', payload);

        // Call the API with the completed payload
        try {
            const response: Address = await AddressesService.createReturnAddressProtectedAddressesPost(payload);
            setReturnAddresses([...returnAddresses, response]); // Update the address state
            setErrorMessage(null);
            setSelectedReturnAddressId(response.id); // Set the newly created address ID to the form
        } catch (error) {
            console.error('Failed to create a new return address:', error);
            setErrorMessage('Failed to create a new return address. Please try again later.');
        }

        // Reset form inputs and close the "Create New Address" form
        setNewReturnAddress({ pgroups: '', house_number: '', street: '', city: '', state: '', zipcode: '', country: '' });
        setIsCreatingReturnAddress(false);
    };

    return (
        <Box
            sx={{
                padding: 4,
                border: '1px solid #ccc',
                borderRadius: '4px',
                marginBottom: 2,
                maxWidth: '600px',
                ...sx,
            }}
        >
            <Typography variant="h6" sx={{ marginBottom: 2 }}>
                Create Shipment
            </Typography>
            {errorMessage && <Typography color="error">{errorMessage}</Typography>}
            <Stack spacing={2}>
                <TextField
                    label="Shipment Name"
                    name="shipment_name"
                    value={newShipment.shipment_name || ''}
                    onChange={handleChange}
                    fullWidth
                    required
                />
                <FormControl fullWidth required>
                    <InputLabel>Contact Person</InputLabel>
                    <Select
                        value={selectedContactId ? selectedContactId.toString() : ''}
                        onChange={handleContactChange}
                        displayEmpty
                    >
                        {contacts.map((person) => (
                            <MenuItem key={person.id} value={person.id.toString()}>
                                {`${person.lastname}, ${person.firstname}`}
                            </MenuItem>
                        ))}
                        <MenuItem value="new">
                            <em>Create New Contact Person</em>
                        </MenuItem>
                    </Select>
                </FormControl>
                {isCreatingContact && (
                    <>
                        <TextField
                            label="First Name"
                            name="firstname"
                            value={newContact.firstname}
                            onChange={(e) => setNewContact({ ...newContact, firstname: e.target.value })}
                            fullWidth
                            required
                        />
                        <TextField
                            label="Last Name"
                            name="lastname"
                            value={newContact.lastname}
                            onChange={(e) => setNewContact({ ...newContact, lastname: e.target.value })}
                            fullWidth
                            required
                        />
                        <TextField
                            label="Phone"
                            name="phone_number"
                            type="tel"
                            value={newContact.phone_number}
                            onChange={(e) => setNewContact({ ...newContact, phone_number: e.target.value })}
                            fullWidth
                            required
                            error={!validatePhoneNumber(newContact.phone_number)}
                            helperText={!validatePhoneNumber(newContact.phone_number) ? 'Invalid phone number' : ''}
                        />
                        <TextField
                            label="Email"
                            name="email"
                            type="email"
                            value={newContact.email}
                            onChange={(e) => setNewContact({ ...newContact, email: e.target.value })}
                            fullWidth
                            required
                            error={!validateEmail(newContact.email)}
                            helperText={!validateEmail(newContact.email) ? 'Invalid email' : ''}
                        />
                        <Button
                            variant="contained"
                            color="primary"
                            onClick={handleSaveNewContact}
                            disabled={!isContactFormValid()}
                        >
                            Save New Contact Person
                        </Button>
                    </>
                )}
                <FormControl fullWidth required>
                    <InputLabel>Proposal Number</InputLabel>
                    <Select
                        value={selectedProposalId ? selectedProposalId.toString() : ''}
                        onChange={handleProposalChange}
                        displayEmpty
                    >
                        {proposals.map((proposal) => (
                            <MenuItem key={proposal.id} value={proposal.id.toString()}>
                                {proposal.number}
                            </MenuItem>
                        ))}
                    </Select>
                </FormControl>
                <FormControl fullWidth required>
                    <InputLabel>Return Address</InputLabel>
                    <Select
                        value={selectedReturnAddressId ? selectedReturnAddressId.toString() : ''}
                        onChange={handleReturnAddressChange}
                        displayEmpty
                    >
                        {returnAddresses.map((address) => {
                            const addressParts = [
                                address.house_number,
                                address.street,
                                address.city,
                                address.zipcode,
                                address.state,
                                address.country
                            ].filter(part => part); // Remove falsy (null/undefined/empty) values

                            return (
                                <MenuItem key={address.id} value={address.id.toString()}>
                                    {addressParts.join(', ')} {/* Join the valid address parts with a comma */}
                                </MenuItem>
                            );
                        })}
                        <MenuItem value="new">
                            <em>Create New Return Address</em>
                        </MenuItem>
                    </Select>
                </FormControl>
                {isCreatingReturnAddress && (
                    <>

                        <TextField
                            label="Street"
                            name="street"
                            value={newReturnAddress.street}
                            onChange={(e) => setNewReturnAddress({ ...newReturnAddress, street: e.target.value })}
                            fullWidth
                            required
                        />
                        <TextField
                            label="Number"
                            name="number"
                            value={newReturnAddress.house_number}
                            onChange={(e) => setNewReturnAddress({ ...newReturnAddress, house_number: e.target.value })}
                            fullWidth
                        />
                        <TextField
                            label="City"
                            name="city"
                            value={newReturnAddress.city}
                            onChange={(e) => setNewReturnAddress({ ...newReturnAddress, city: e.target.value })}
                            fullWidth
                            required
                        />
                        <TextField
                            label="State"
                            name="state"
                            value={newReturnAddress.state}
                            onChange={(e) => setNewReturnAddress({ ...newReturnAddress, state: e.target.value })}
                            fullWidth
                        />
                        <TextField
                            label="Zip Code"
                            name="zipcode"
                            value={newReturnAddress.zipcode}
                            onChange={(e) => setNewReturnAddress({ ...newReturnAddress, zipcode: e.target.value })}
                            fullWidth
                            required
                            error={!validateZipCode(newReturnAddress.zipcode)}
                            helperText={!validateZipCode(newReturnAddress.zipcode) ? 'Invalid zip code' : ''}
                        />
                        <TextField
                            label="Country"
                            name="country"
                            value={newReturnAddress.country}
                            onChange={handleCountryInputChange} // Ensure this matches the function name exactly
                            fullWidth
                            required
                            error={!newReturnAddress.country} // Optional: Add an error indicator if the input is empty
                            helperText={!newReturnAddress.country ? 'Country is required' : ''}
                        />

                        {/* Render country suggestions below the input field */}
                        {countrySuggestions.length > 0 && (
                            <Box sx={{ marginTop: '0.5rem', border: '1px solid #ccc', borderRadius: '4px', padding: '0.5rem' }}>
                                {countrySuggestions.map((suggestion, index) => (
                                    <Typography
                                        key={index}
                                        sx={{
                                            cursor: 'pointer',
                                            padding: '0.2rem 0',
                                            '&:hover': {
                                                backgroundColor: '#f0f0f0',
                                            },
                                        }}
                                        onClick={() => {
                                            // Update country field with selected suggestion
                                            setNewReturnAddress({ ...newReturnAddress, country: suggestion });
                                            setCountrySuggestions([]); // Clear suggestions
                                        }}
                                    >
                                        {suggestion}
                                    </Typography>
                                ))}
                            </Box>
                        )}
                        <Button
                            variant="contained"
                            color="primary"
                            onClick={handleSaveNewReturnAddress}
                            disabled={!isAddressFormValid()}
                        >
                            Save New Return Address
                        </Button>
                    </>
                )}
                <Box
                    sx={{
                        position: 'relative',
                    }}
                >
                    <TextField
                        label="Comments"
                        name="comments"
                        fullWidth
                        multiline
                        rows={4}
                        value={newShipment.comments || ''}
                        onChange={handleChange}
                        inputProps={{ maxLength: MAX_COMMENTS_LENGTH }}
                    />
                    <Typography
                        variant="caption"
                        color={newShipment.comments && newShipment.comments.length > MAX_COMMENTS_LENGTH ? 'error' : 'textSecondary'}
                        sx={{
                            position: 'absolute',
                            bottom: 8,
                            right: 8,
                        }}
                    >
                        {MAX_COMMENTS_LENGTH - (newShipment.comments?.length || 0)} characters remaining
                    </Typography>
                </Box>
                <Stack direction="row" spacing={2} justifyContent="flex-end">
                    <Button variant="outlined" color="error" onClick={onCancel}>Cancel</Button>
                    <Button
                        variant="contained"
                        color="primary"
                        onClick={handleSaveShipment}
                        disabled={(newShipment.comments?.length ?? 0) > MAX_COMMENTS_LENGTH}
                    >
                        Save Shipment
                    </Button>
                </Stack>
            </Stack>
        </Box>
    );
};

export default ShipmentForm;