import * as React from 'react';
import {
    Box, Button, TextField, Typography, Select, MenuItem, Stack, FormControl, InputLabel
} from '@mui/material';
import { SelectChangeEvent } from '@mui/material';
import { SxProps } from '@mui/system';
import {
    ContactPersonCreate, ContactPerson, Address, Proposal, ContactsService, AddressesService, AddressCreate, ProposalsService,
    OpenAPI, ShipmentCreate, ShipmentsService
} from '../../openapi';
import { useEffect } from 'react';

const MAX_COMMENTS_LENGTH = 200;

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

const ShipmentForm: React.FC<ShipmentFormProps> = ({ sx = {}, onCancel, refreshShipments }) => {
    const [contactPersons, setContactPersons] = React.useState<ContactPerson[]>([]);
    const [returnAddresses, setReturnAddresses] = React.useState<Address[]>([]);
    const [proposals, setProposals] = React.useState<Proposal[]>([]);
    const [isCreatingContactPerson, setIsCreatingContactPerson] = React.useState(false);
    const [isCreatingReturnAddress, setIsCreatingReturnAddress] = React.useState(false);
    const [newContactPerson, setNewContactPerson] = React.useState<ContactPersonCreate>({
        firstname: '', lastname: '', phone_number: '', email: ''
    });
    const [newReturnAddress, setNewReturnAddress] = React.useState<Omit<Address, 'id'>>({
        street: '', city: '', zipcode: '', country: ''
    });
    const [newShipment, setNewShipment] = React.useState<Partial<ShipmentCreate>>({
        shipment_name: '', shipment_status: 'In preparation', comments: ''
    });
    const [selectedContactPersonId, setSelectedContactPersonId] = 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(() => {
        const isTestEnv = import.meta.env.MODE === 'test';
        OpenAPI.BASE = isTestEnv
            ? import.meta.env.VITE_OPENAPI_BASE_TEST
            : import.meta.env.VITE_OPENAPI_BASE_DEV;

        const getContacts = async () => {
            try {
                const c: ContactPerson[] = await ContactsService.getContactsContactsGet();
                setContactPersons(c);
            } catch {
                setErrorMessage('Failed to load contact persons. Please try again later.');
            }
        };

        const getAddresses = async () => {
            try {
                const a: Address[] = await AddressesService.getReturnAddressesAddressesGet();
                setReturnAddresses(a);
            } catch {
                setErrorMessage('Failed to load return addresses. Please try again later.');
            }
        };

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

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

    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 } = newContactPerson;

        if (isCreatingContactPerson) {
            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 (!selectedContactPersonId || !selectedReturnAddressId || !selectedProposalId) return false;

        if (isCreatingContactPerson && !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 at all
            shipment_status: newShipment.shipment_status || 'In preparation',
            comments: newShipment.comments || '',
            contact_person_id: selectedContactPersonId!,
            return_address_id: selectedReturnAddressId!,
            proposal_id: selectedProposalId!,
            dewars: newShipment.dewars || []
        };

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

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

    const handleContactPersonChange = (event: SelectChangeEvent) => {
        const value = event.target.value;
        if (value === 'new') {
            setIsCreatingContactPerson(true);
            setSelectedContactPersonId(null);
        } else {
            setIsCreatingContactPerson(false);
            setSelectedContactPersonId(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 handleSaveNewContactPerson = async () => {
        if (!isContactFormValid()) {
            setErrorMessage('Please fill in all new contact person fields correctly.');
            return;
        }

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

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

        try {
            const newPerson: ContactPerson = await ContactsService.createContactContactsPost(payload);
            setContactPersons([...contactPersons, newPerson]);
            setErrorMessage(null);
            setSelectedContactPersonId(newPerson.id);
        } catch (error) {
            console.error('Failed to create a new contact person:', error);
            setErrorMessage('Failed to create a new contact person. Please try again later.');
        }

        setNewContactPerson({ firstname: '', lastname: '', phone_number: '', email: '' });
        setIsCreatingContactPerson(false);
    };

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

        const payload: AddressCreate = {
            street: newReturnAddress.street,
            city: newReturnAddress.city,
            zipcode: newReturnAddress.zipcode,
            country: newReturnAddress.country,
        };

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

        try {
            const response: Address = await AddressesService.createReturnAddressAddressesPost(payload);
            setReturnAddresses([...returnAddresses, response]);
            setErrorMessage(null);
            setSelectedReturnAddressId(response.id);
        } catch (error) {
            console.error('Failed to create a new return address:', error);
            setErrorMessage('Failed to create a new return address. Please try again later.');
        }

        setNewReturnAddress({ street: '', city: '', 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={selectedContactPersonId ? selectedContactPersonId.toString() : ''}
                        onChange={handleContactPersonChange}
                        displayEmpty
                    >
                        {contactPersons.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>
                {isCreatingContactPerson && (
                    <>
                        <TextField
                            label="First Name"
                            name="firstname"
                            value={newContactPerson.firstname}
                            onChange={(e) => setNewContactPerson({ ...newContactPerson, firstname: e.target.value })}
                            fullWidth
                            required
                        />
                        <TextField
                            label="Last Name"
                            name="lastname"
                            value={newContactPerson.lastname}
                            onChange={(e) => setNewContactPerson({ ...newContactPerson, lastname: e.target.value })}
                            fullWidth
                            required
                        />
                        <TextField
                            label="Phone"
                            name="phone_number"
                            type="tel"
                            value={newContactPerson.phone_number}
                            onChange={(e) => setNewContactPerson({ ...newContactPerson, phone_number: e.target.value })}
                            fullWidth
                            required
                            error={!validatePhoneNumber(newContactPerson.phone_number)}
                            helperText={!validatePhoneNumber(newContactPerson.phone_number) ? 'Invalid phone number' : ''}
                        />
                        <TextField
                            label="Email"
                            name="email"
                            type="email"
                            value={newContactPerson.email}
                            onChange={(e) => setNewContactPerson({ ...newContactPerson, email: e.target.value })}
                            fullWidth
                            required
                            error={!validateEmail(newContactPerson.email)}
                            helperText={!validateEmail(newContactPerson.email) ? 'Invalid email' : ''}
                        />
                        <Button
                            variant="contained"
                            color="primary"
                            onClick={handleSaveNewContactPerson}
                            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) => (
                            <MenuItem key={address.id} value={address.id.toString()}>
                                {`${address.street}, ${address.city}, ${address.zipcode}, ${address.country}`}
                            </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="City"
                            name="city"
                            value={newReturnAddress.city}
                            onChange={(e) => setNewReturnAddress({ ...newReturnAddress, city: e.target.value })}
                            fullWidth
                            required
                        />
                        <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={(e) => setNewReturnAddress({ ...newReturnAddress, country: e.target.value })}
                            fullWidth
                            required
                        />
                        <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;