﻿import { useState, useEffect } from "react";
import {
    Dialog,
    DialogTitle,
    DialogContent,
    TextField,
    Autocomplete,
    DialogActions,
    Button,
    Checkbox,
    FormControl,
    FormControlLabel,
    Box,
    MenuItem,
    Select,
    InputLabel
} from "@mui/material";
import VisibilityIcon from '@mui/icons-material/Visibility';

import Template from "@/types/template";
import Mailing from "@/types/mailing";
import Target from "@/types/target";
import EmailList from "@/components/forms/EmailList";
import TestEmailList from "@/types/testEmailList";
import TemplateViewer from "@/components/modals/TemplateViewer"
import TargetSampleModal from "@/components/modals/TargetSampleModal"
import { useSetupData, SetupData } from "@/context/SetupDataContext";
import { useForm, Controller, Resolver } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";

import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import dayjs, { Dayjs } from 'dayjs'; // Import Dayjs for date handling
import utc from 'dayjs/plugin/utc'; // Import the UTC plugin
import { toast } from "react-toastify";

dayjs.extend(utc);

type MailingEditProps = {
    open: boolean;
    mailing: Mailing | null;
    onClose: (reason: 'backdropClick' | 'escapeKeyDown' | 'saved' | 'cancelled') => void;
    onSave: (updatedMailing: Mailing) => void;
};

//const statusOptions = [
//    { code: 'C', name: 'Cancelled' },
//    { code: 'ED', name: 'Editing' },
//    { code: 'ER', name: 'Error' },
//    { code: 'QE', name: 'Queueing Error' },
//    { code: 'S', name: 'Sent' },
//    { code: 'SC', name: 'Scheduled' },
//    { code: 'SD', name: 'Sending' },
//];

const recurringTypeOptions = [
    { code: 'D', name: 'Daily' },
    { code: 'M', name: 'Monthly' },
    { code: 'W', name: 'Weekly' },
];

const schema = yup.object().shape({
    id: yup.number().nullable(),
    name: yup.string().required("Name is required")
        .test("unique-name", "Name must be unique", async function (value) {
            if (value.length === 0)
                return true;
            return await nameIsAvailable(this.parent.id, value);
        }), 
    description: yup.string().default(""),
    templateId: yup.number().typeError("Template is required").required("Template is required").test("valid-template", "Invalid template", function (value) {
        const setupData = this.options.context?.setupData as SetupData;
        return setupData.templates.some(t => t.id === value);
    }),
    targetId: yup.number().typeError("Target is required").required("Target is required").test("valid-target", "Invalid target", function (value) {
        const setupData = this.options.context?.setupData as SetupData;
        return setupData.targets.some(t => t.id === value);
    }),
    statusCode: yup.string().default("ED"),
    scheduleDate: yup.string()
        .nullable()
        .when("$scheduleForLater", (scheduleForLater, schema) => {
            const isScheduledForLater = scheduleForLater[0] ?? false;
            return isScheduledForLater
                ? schema
                    .required("Schedule date is required when scheduled for later")
                    .matches(
                        /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/,
                        "Schedule date must be a valid UTC ISO string (e.g., 'YYYY-MM-DDTHH:mm:ssZ')"
                    )
                    .test("is-future", "Schedule date must be in the future", (value) => {
                        if (!value) return true; // Nullable when not required
                        return dayjs(value).isAfter(dayjs());
                    })
                : schema.nullable();
        }),

    //scheduleDate: yup.date().nullable(),

    //    .when("statusCode", {
    //    is: (value: string) => value === "SC" || value === "SD", // String comparison
    //    then: (schema) => schema.required("Schedule date is required for scheduled or sending status"),
    //    otherwise: (schema) => schema.nullable(),
    //}),
    sentDate: yup.date().nullable().default(null),
    sessionActivityId: yup.string().nullable(),
    recurringTypeCode: yup
        .string()
        .nullable()
        .when("$recurring", (recurring, schema) => { // Use context variable
            const isRecurring = recurring[0] ?? false; 
            return isRecurring
                ? schema.oneOf(recurringTypeOptions.map((r) => r.code), "Invalid recurring type")
                : schema.nullable();
        }),
        
    recurringStartDate: yup.string()
        .nullable()
        .when("$recurring", (recurring, schema) => {
            const isRecurring = recurring[0] ?? false;
            return isRecurring
                ? schema
                    .required("Recurring start date is required when recurring")
                    .matches(
                        /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/,
                        "Recurring start date must be a valid UTC ISO string (e.g., 'YYYY-MM-DDTHH:mm:ssZ')"
                    )
                    .test("is-future", "Recurring start date must be in the future", (value) => {
                        if (!value) return true; // Nullable when not required
                        return dayjs(value).isAfter(dayjs());
                    })
                : schema.nullable();
        }),

        //.when("recurringTypeCode", {
        //is: (value: string) => value !== "" && value !== null, // String comparison for "None"
        //then: (schema) => schema.required("Recurring start date is required when recurring type is set"),
        //otherwise: (schema) => schema.nullable(),
    //}),
});

const nameIsAvailable = async (id: number, name: string) => {
    const response = await fetch(`/api/mailings/available?${id > 0 ? "id=" + id + "&" : ""}name=${name}`);
    const data = await response.json();
    return data.available;
};
const getNextAvailableName = async (id: number, name: string) => {
    const response = await fetch(`/api/mailings/nextavailablename?${id > 0 ? "id=" + id + "&" : ""}name=${name}`);
    const data = await response.json();
    return data.name;
};

const defaultMailing: Mailing = {
    id: 0,
    name: "",
    description: "",
    templateId: 0,
    targetId: 0,
    statusCode: "ED",
    scheduleDate: null,
    sentDate: null,
    sessionActivityId: null,
    recurringTypeCode: null,
    recurringStartDate: null,
};

const MailingEdit = ({ open, mailing, onClose, onSave }: MailingEditProps) => {
    const isNew = !mailing || mailing.id === 0;
    const setupData: SetupData = useSetupData();
    const [approved, setApproved] = useState<boolean>(false);
    const [recurring, setRecurring] = useState<boolean>(false);
    const [scheduleForLater, setScheduleForLater] = useState<boolean>(false);
    const [testEmailListId, setTestEmailListId] = useState<number | null>(null);
    const [emails, setEmails] = useState<string[]>([]); // State for email array
    const [templateViewerOpen, setTemplateViewerOpen] = useState<boolean>(false);
    const [currentTemplate, setCurrentTemplate] = useState<Template | null>(null);
    const [TargetSampleModalOpen, setTargetSampleModalOpen] = useState<boolean>(false);
    const [currentTarget, setCurrentTarget] = useState<Target | null>(null);

    const { register, trigger, control, handleSubmit, reset, formState: { errors } } = useForm<Mailing>({
        mode: "onBlur",
        defaultValues: {
            ...(mailing || defaultMailing),
        },
        resolver: yupResolver(schema) as Resolver<Mailing>,
        context: { setupData, scheduleForLater, recurring },
    });

    const [loading, setLoading] = useState(false);

    useEffect(() => {
        const initializeMailingEdit = async () => {
            if (open) {
                if (mailing) {
                    mailing.scheduleDate = null;
                    mailing.recurringTypeCode = null;
                    mailing.recurringStartDate = null;
                    if (mailing.id == 0) {
                        mailing.name = await getNextAvailableName(mailing.id, mailing.name);
                    }
                }
                setApproved(false);
                setRecurring(false);
                setScheduleForLater(false);
                reset(mailing || defaultMailing, { keepDefaultValues: true });
                if (setupData.testEmailLists.length > 0) {
                    setTestEmailListId(setupData.testEmailLists[0].id);
                    setEmails(setupData.testEmailLists[0].emails);
                } else {
                    setTestEmailListId(null);
                    setEmails([]);
                }
                if (mailing?.templateId) {
                    const template = setupData.templates.find(t => t.id === mailing.templateId) || null;
                    setCurrentTemplate(template);
                } else {
                    setCurrentTemplate(null);
                }
                if (mailing?.targetId) {
                    const target = setupData.targets.find(t => t.id === mailing.targetId) || null;
                    setCurrentTarget(target);
                } else {
                    setCurrentTarget(null);
                }
            }
        };

        initializeMailingEdit();
    }, [open, mailing, reset, setupData.testEmailLists, setupData.targets, setupData.templates]);

    const handleSave = async (formData: Mailing) => {
        const apiUrl = isNew ? "/api/mailings" : `/api/mailings/${formData.id}`;
        const method = isNew ? "POST" : "PUT";
        setLoading(true);

        if (approved) {
            formData.statusCode = "SC";
            if (!scheduleForLater) {
                formData.scheduleDate = null;
            }
            if (!recurring) {
                formData.recurringTypeCode = null;
                formData.recurringStartDate = null;
            }
        }
        else {
            formData.statusCode = "ED";
            formData.scheduleDate = null;
            formData.recurringTypeCode = null;
            formData.recurringStartDate = null;
        }
        try {
            const jsonPayload = JSON.stringify(formData);
            const response = await fetch(apiUrl, {
                method: method,
                headers: { "Content-Type": "application/json" },
                body: jsonPayload,
            });

            if (!response.ok) throw new Error(isNew ? "Failed to create" : "Failed to update");

            const updatedMailing = await response.json();
            onSave(updatedMailing);
            onClose('saved');
        } catch (error) {
            console.error("Update error:", error);
        } finally {
            setLoading(false);
        }
    };

    const handleEmailsChange = (newEmails: string[]) => {
        setEmails(newEmails);
    };

    const handleTestMailing = async () => {
        setLoading(true); // Show loading state

        const isValid = await trigger();
        if (!isValid) {
            console.log("Form is invalid, cannot test mailing");
            setLoading(false);
            return;
        }

        try {
            // Get the current form data
            const formData = control._formValues as Mailing;

            // Prepare the payload matching TestMailingDto
            const testMailingPayload = {
                mailing: formData,
                emailAddresses: emails,
            };

            // Make the API call to /api/mailings/test
            const response = await fetch("/api/mailings/test", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify(testMailingPayload),
            });

            if (!response.ok) {
                throw new Error("Failed to test mailing");
            }

            toast.success("Test mailing sent successfully");
            console.log("Test mailing sent successfully");
        } catch (error) {
            console.error("Test mailing error:", error);
            toast.error("Failed to send test mailing");
        } finally {
            setLoading(false); // Reset loading state
        }
    };

    const handleTestEmailListChange = (list: TestEmailList | null) => {
        if (list) {
            setTestEmailListId(list.id);
            setEmails(list.emails);
        }
    }
    const handleApprovedChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setApproved(event.target.checked);
    };
    const handleRecurringChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setRecurring(event.target.checked);
    };
    const handleScheduleForLaterChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setScheduleForLater(event.target.checked);
    };
    const handleTemplateViewerOpen = () => {
        setTemplateViewerOpen(!templateViewerOpen);
    };
    const handleTargetSampleModalOpen = () => {
        setTargetSampleModalOpen(!TargetSampleModalOpen);
    };
    return (
        <LocalizationProvider dateAdapter={AdapterDayjs}> {/* Wrap with LocalizationProvider */}
            <Dialog open={open} onClose={(_, reason) => { onClose(reason); }} maxWidth="sm" fullWidth disableEscapeKeyDown >
                <DialogTitle>{isNew ? "Add Mailing" : "Edit Mailing id=" + mailing?.id}</DialogTitle>
                <DialogContent>
                    <TextField
                        {...register("name")}
                        label="Name"
                        fullWidth
                        margin="dense"
                        error={!!errors.name}
                        helperText={errors.name?.message}
                    />
                    <TextField
                        {...register("description")}
                        label="Description"
                        fullWidth
                        margin="dense"
                        error={!!errors.description}
                        helperText={errors.description?.message}
                    />

                    <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
                        <Controller
                            name="templateId"
                            control={control}
                            render={({ field }) => (
                                <Autocomplete
                                    {...field}
                                    options={setupData.templates}
                                    getOptionLabel={(option) => option.name}
                                    value={setupData.templates.find(t => t.id === field.value) || null}
                                    onChange={(_, newValue) => {
                                        field.onChange(newValue ? newValue.id : null);
                                        trigger("templateId");
                                        setCurrentTemplate(newValue);
                                    }}
                                    renderInput={(params) => (
                                        <TextField
                                            {...params}
                                            label="Template"
                                            fullWidth
                                            margin="dense"
                                            error={!!errors.templateId}
                                            helperText={errors.templateId?.message}
                                        />
                                    )}
                                    sx={{ flexGrow: 1 }}
                                />
                            )}
                        />
                        {currentTemplate && (
                            <Button
                                onClick={handleTemplateViewerOpen}
                                variant="outlined"
                                startIcon={<VisibilityIcon />}
                                sx={{ height: '100%', alignSelf: 'center' }}
                            >
                                View
                            </Button>
                        )}
                    </Box>

                    <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
                    <Controller
                        name="targetId"
                        control={control}
                        render={({ field }) => (
                            <Autocomplete
                                {...field}
                                options={setupData.targets}
                                getOptionLabel={(option) => option.name}
                                value={setupData.targets.find(t => t.id === field.value) || null}
                                onChange={(_, newValue) => {
                                    field.onChange(newValue ? newValue.id : null);
                                    trigger("targetId");
                                    setCurrentTarget(newValue);
                                }}
                                renderInput={(params) => (
                                    <TextField
                                        {...params}
                                        label="Target"
                                        fullWidth
                                        margin="dense"
                                        error={!!errors.targetId}
                                        helperText={errors.targetId?.message}
                                    />
                                )}
                                sx={{ flexGrow: 1 }}
                            />
                        )}
                        />
                        {currentTarget && (
                            <Button
                                onClick={handleTargetSampleModalOpen}
                                variant="outlined"
                                startIcon={<VisibilityIcon />}
                                sx={{ height: '100%', alignSelf: 'center' }}
                            >
                                View
                            </Button>
                        )}
                    </Box>
                    <Autocomplete
                        options={setupData.testEmailLists}
                        getOptionLabel={(option) => option.name}
                        value={setupData.testEmailLists.find(t => t.id === testEmailListId) || null}
                        onChange={(_, newValue) => handleTestEmailListChange(newValue)}
                        renderInput={(params) => (
                            <TextField
                                {...params}
                                label="Test Email List"
                                fullWidth
                                margin="dense"
                            />
                        )}
                    />
                    <EmailList emails={emails} onEmailTextChange={handleEmailsChange} />
                    <Button onClick={handleTestMailing} disabled={loading}>Test Mailing</Button>
                    <Box>
                        <FormControlLabel control={<Checkbox checked={approved} onChange={handleApprovedChange} />} label="Approved" />
                    </Box>
                    {approved && (<>
                        <Box sx={{ display: 'flex', flexDirection: 'column', ml: 3 }}>
                            <FormControlLabel control={<Checkbox checked={recurring} onChange={handleRecurringChange} />} label="Recurring Mailing" />
                            {recurring && (<>
                                <FormControl fullWidth margin="dense">
                                    <InputLabel id="recurring-type-select-label">Recurring Type</InputLabel>
                                    <Controller
                                        name="recurringTypeCode"
                                        control={control}
                                        render={({ field }) => (
                                            <Select
                                                {...field}
                                                labelId="recurring-type-select-label"
                                                id="recurring-type-select"
                                                label="Recurring Type"
                                                value={field.value || ''}
                                                onChange={(e) => {
                                                    field.onChange(e.target.value);
                                                    trigger("recurringTypeCode");
                                                }}
                                                error={!!errors.recurringTypeCode}
                                            >
                                                <MenuItem value="">
                                                    <em>None</em>
                                                </MenuItem>
                                                {recurringTypeOptions.map((option) => (
                                                    <MenuItem key={option.code} value={option.code}>
                                                        {option.name}
                                                    </MenuItem>
                                                ))}
                                            </Select>
                                        )}
                                    />
                                    {errors.recurringTypeCode && (
                                        <span style={{ color: 'red', fontSize: '0.75rem' }}>
                                            {errors.recurringTypeCode.message}
                                        </span>
                                    )}
                                </FormControl>
                                <Controller
                                    name="recurringStartDate"
                                    control={control}
                                    render={({ field }) => (
                                        <DateTimePicker
                                            label="Recurring Start Date"
                                            value={field.value ? dayjs(field.value) : null} // Convert to Dayjs
                                            onChange={(newValue: Dayjs | null) => {
                                                const utcString = newValue ? newValue.utc().format("YYYY-MM-DDTHH:mm:ss[Z]") : null;
                                                field.onChange(utcString);
                                                trigger("recurringStartDate");
                                            }}
                                            slotProps={{
                                                textField: {
                                                    fullWidth: true,
                                                    margin: "dense",
                                                    error: !!errors.recurringStartDate,
                                                    helperText: errors.recurringStartDate?.message,
                                                },
                                            }}
                                            minDateTime={dayjs()} // Enforce future date in UI
                                        />
                                    )}
                                />
                            </>)}
                            <FormControlLabel control={<Checkbox checked={scheduleForLater} onChange={handleScheduleForLaterChange} />} label="Schedule for Later" />
                            {scheduleForLater && (
                                <Controller
                                    name="scheduleDate"
                                    control={control}
                                    render={({ field }) => (
                                        <DateTimePicker
                                            label="Schedule Date"
                                            value={field.value ? dayjs(field.value) : null} // Convert to Dayjs
                                            onChange={(newValue: Dayjs | null) => {
                                                const utcString = newValue ? newValue.utc().format("YYYY-MM-DDTHH:mm:ss[Z]") : null;
                                                field.onChange(utcString);
                                                trigger("scheduleDate");
                                            }}
                                            slotProps={{
                                                textField: {
                                                    fullWidth: true,
                                                    margin: "dense",
                                                    error: !!errors.scheduleDate,
                                                    helperText: errors.scheduleDate?.message,
                                                },
                                            }}
                                            minDateTime={dayjs()} // Enforce future date in UI
                                        />
                                    )}
                                />
                            )}
                        </Box>
                    </>)}

                {templateViewerOpen && (
                    <TemplateViewer
                        open={templateViewerOpen}
                        template={currentTemplate!}
                        onClose={() => { setTemplateViewerOpen(false) }}
                    />
                )}
                {TargetSampleModalOpen && (
                    <TargetSampleModal
                        open={TargetSampleModalOpen}
                        target={currentTarget!}
                        onClose={() => { setTargetSampleModalOpen(false) }}
                    />
                )}
                </DialogContent>
                <DialogActions>
                    <Button onClick={() => { onClose( 'cancelled'); }} disabled={loading}>Cancel</Button>
                    <Button onClick={handleSubmit(handleSave)} color="primary" disabled={loading}>
                        {loading ? "Saving..." : "Save"}
                    </Button>
                </DialogActions>
            </Dialog>
        </LocalizationProvider>
    );
};

export default MailingEdit;