import { useFormik } from "formik";
import * as Yup from "yup";
import Modal from "../../components/Modals";
import Select from "../../components/Select";
import Datepicker from "../../components/Datepicker";
import Timepicker from "../../components/Timepicker";
import api from '../../api/axios';
import { toast } from 'react-toastify';
import { useEffect, useState } from "react";

interface Props {
    open: boolean;
    onClose: () => void;
    onSave: (data: any) => void;
}

interface CourseOption {
    value: string;
    label: string;
    duration: string;
    durationMonths: number;
    durationHours: number; // Added for schedule calculation
}

type OptionType = {
    value: string;
    label: string;
};

const AddBatch = ({ open, onClose, onSave }: Props) => {
    const [courseOptions, setCourseOptions] = useState<CourseOption[]>([]);
    const [roomOptions, setRoomOptions] = useState<OptionType[]>([]);
    const [trainerOptions, setTrainerOptions] = useState<OptionType[]>([]);
    const [staffOptions, setStaffOptions] = useState<OptionType[]>([]);
    const [isCheckingAvailability, setIsCheckingAvailability] = useState(false);
    const [availabilityConflicts, setAvailabilityConflicts] = useState<any[]>([]);

    const modeOptions = [
        { value: "online", label: "Online" },
        { value: "offline", label: "Offline" },
        { value: "hybrid", label: "Hybrid" },
    ];

    const scheduleOptions = [
        { value: "weekdays", label: "Weekdays (Mon-Fri)" },
        { value: "weekends", label: "Weekends (Sat-Sun)" },
    ];

    // Extract months and hours from duration string
    const extractDurationInfo = (duration: any) => {
        if (!duration) return { months: 0, hours: 0 };

        const durationStr = String(duration);
        let months = 0;
        let hours = 0;

        // Extract months
        const monthMatch = durationStr.match(/(\d+)\s*months?/i);
        if (monthMatch) {
            months = parseInt(monthMatch[1]);
        }

        // Extract hours
        const hourMatch = durationStr.match(/(\d+)\s*(?:hrs?|hours?)/i);
        if (hourMatch) {
            hours = parseInt(hourMatch[1]);
        }

        // If no specific format found, try to extract any number
        if (months === 0 && hours === 0) {
            const numMatch = durationStr.match(/(\d+)/);
            if (numMatch) {
                // Assume it's months if > 12, otherwise hours
                const num = parseInt(numMatch[1]);
                if (num > 12) {
                    hours = num;
                } else {
                    months = num;
                }
            }
        }

        return { months, hours };
    };

    // Calculate end date based on course duration
    const calculateEndDate = (startDate: string, courseId: string) => {
        if (!startDate || !courseId) return;

        const selectedCourse = courseOptions.find(c => c.value === courseId);
        if (!selectedCourse || selectedCourse.durationMonths === 0) return;

        const start = new Date(startDate);
        const end = new Date(start);
        end.setMonth(end.getMonth() + selectedCourse.durationMonths);

        // Adjust for date overflow
        if (end.getDate() !== start.getDate()) {
            end.setDate(0);
        }

        const endDateStr = end.toISOString().split('T')[0];
        formik.setFieldValue("end_date", endDateStr);
    };

    // Fetch staff by course skills
    const fetchStaffByCourseSkills = async (courseId: string) => {
        if (!courseId) return;

        try {
            const response = await api.get(`/staff/skills`, {
                params: { course_id: courseId }
            });

            if (response.data.status === 200) {
                const options = response.data.data.map((staff: any) => ({
                    value: staff.id,
                    label: staff.staff_name
                }));
                setTrainerOptions(options);
                setStaffOptions(options);
            }
        } catch (error) {
            console.error('Error fetching staff by skills:', error);
            toast.error('Failed to load staff based on course skills');
        }
    };

    // Check staff availability
    const checkStaffAvailability = async (staffIds: number[], showToast = true) => {
        const { start_date, end_date, start_time, end_time } = formik.values;

        if (!start_date || !end_date || !start_time || !end_time || staffIds.length === 0) {
            return true;
        }

        setIsCheckingAvailability(true);
        try {
            const response = await api.post('/staff/check-availability', {
                staff_id: staffIds,
                start_date,
                end_date,
                start_time,
                end_time
            });

            if (response.data.status === 200) {
                if (!response.data.available) {
                    setAvailabilityConflicts(response.data.conflicts);
                    if (showToast) {
                        toast.error('Staff member has scheduling conflicts!');
                    }
                    return false;
                } else {
                    setAvailabilityConflicts([]);
                    return true;
                }
            }
            return true;
        } catch (error) {
            console.error('Error checking staff availability:', error);
            return true;
        } finally {
            setIsCheckingAvailability(false);
        }
    };

    // Fetch courses
    useEffect(() => {
        const fetchCourses = async () => {
            try {
                const response = await api.get('/course/lists');

                if (response.data.status === 200 || response.data.status === true) {
                    const options = response.data.data.map((cat: any) => {
                        const { months, hours } = extractDurationInfo(cat.duration);
                        return {
                            value: cat.id,
                            label: `${cat.course_name} (${cat.duration})`,
                            duration: cat.duration,
                            durationMonths: months,
                            durationHours: hours
                        };
                    });
                    setCourseOptions(options);
                }
            } catch (error) {
                console.error('Error fetching courses:', error);
                toast.error('Failed to load courses');
            }
        };

        if (open) fetchCourses();
    }, [open]);

    // Fetch rooms
    useEffect(() => {
        const fetchRooms = async () => {
            try {
                const response = await api.get('/room/list');
                if (response.data.status === 200) {
                    const options = response.data.data.map((cat: any) => ({
                        value: cat.id,
                        label: cat.name
                    }));
                    setRoomOptions(options);
                }
            } catch (error) {
                console.error('Error fetching rooms:', error);
                toast.error('Failed to load rooms');
            }
        };

        if (open) fetchRooms();
    }, [open]);

    const validationSchema = Yup.object({
        batch_name: Yup.string().required("Batch name is required"),
        description: Yup.string(),
        start_date: Yup.string().required("Start date required"),
        end_date: Yup.string().required("End date required"),
        start_time: Yup.string().required("Start time required"),
        end_time: Yup.string().required("End time required"),
        mode: Yup.string().required("Mode required"),
        schedule: Yup.string().required("Schedule days required"),
        capacity: Yup.number().required("Capacity required").min(1, "Capacity must be at least 1"),
        course_id: Yup.string().required("Course required"),
        room_id: Yup.string().when('mode', {
            is: (mode: string) => mode === 'offline' || mode === 'hybrid',
            then: (schema) => schema.required("Room is required for offline/hybrid mode"),
            otherwise: (schema) => schema.nullable()
        }),
        trainer_id: Yup.string().required("Trainer required"),
        co_trainer: Yup.string().nullable(),
        support_staff: Yup.string().nullable(),
    });

    const formik = useFormik({
        initialValues: {
            batch_name: "",
            description: "",
            start_date: "",
            end_date: "",
            start_time: "",
            end_time: "",
            mode: "",
            schedule: "",
            capacity: "",
            room_id: "",
            course_id: "",
            trainer_id: "",
            co_trainer: "",
            support_staff: "",
        },
        validationSchema,
        onSubmit: async (values) => {
            const staffIds = [values.trainer_id, values.co_trainer, values.support_staff]
                .filter(id => id && id !== "").map(id => Number(id));

            const isAvailable = await checkStaffAvailability(staffIds, true);

            if (!isAvailable) {
                toast.error('Please resolve scheduling conflicts before submitting');
                return;
            }

            try {
                const response = await api.post('/batch/add', values);
                if (response.data.status) {
                    toast.success('Batch created successfully with schedule!');
                    onSave(response.data.data);
                    onClose();
                    formik.resetForm();
                }
            } catch (error: any) {
                console.error('Error creating batch:', error);
                toast.error(error.response?.data?.message || 'Failed to create batch');
            }
        },
    });

    // Auto-calculate end date
    useEffect(() => {
        if (formik.values.start_date && formik.values.course_id && courseOptions.length > 0) {
            calculateEndDate(formik.values.start_date, formik.values.course_id);
        }
    }, [formik.values.start_date, formik.values.course_id, courseOptions]);

    // Fetch staff based on course
    useEffect(() => {
        if (formik.values.course_id) {
            fetchStaffByCourseSkills(formik.values.course_id);
        }
    }, [formik.values.course_id]);

    // Check availability on changes
    useEffect(() => {
        const timer = setTimeout(() => {
            const staffIds = [formik.values.trainer_id, formik.values.co_trainer, formik.values.support_staff]
                .filter(id => id && id !== "").map(id => Number(id));

            if (staffIds.length > 0 && formik.values.start_date && formik.values.end_date &&
                formik.values.start_time && formik.values.end_time) {
                checkStaffAvailability(staffIds, false);
            }
        }, 500);

        return () => clearTimeout(timer);
    }, [formik.values.trainer_id, formik.values.co_trainer, formik.values.support_staff,
        formik.values.start_date, formik.values.end_date, formik.values.start_time, formik.values.end_time]);

    const formatDate = (date: Date) => {
        return date.toISOString().split('T')[0];
    };

    return (
        <Modal
            open={open}
            onClose={onClose}
            title="Create Batch"
            maxWidth="max-w-4xl"
            footer={
                <>
                    <button onClick={onClose} className="btn btn-outline-danger" type="button">
                        Cancel
                    </button>
                    <button
                        onClick={() => formik.handleSubmit()}
                        className="btn btn-primary"
                        type="button"
                        disabled={isCheckingAvailability || availabilityConflicts.length > 0}
                    >
                        {isCheckingAvailability ? 'Checking Availability...' : 'Create Batch & Generate Schedule'}
                    </button>
                </>
            }
        >
            <form className="grid grid-cols-1 md:grid-cols-2 gap-4">
                <div>
                    <label>Batch Name <span className="text-danger">*</span></label>
                    <input
                        name="batch_name"
                        className="form-input w-full"
                        value={formik.values.batch_name}
                        onChange={formik.handleChange}
                        onBlur={formik.handleBlur}
                    />
                    {formik.errors.batch_name && formik.touched.batch_name && (
                        <div className="text-danger text-xs">{formik.errors.batch_name}</div>
                    )}
                </div>

                <div>
                    <label>Description</label>
                    <textarea
                        name="description"
                        rows={1}
                        className="form-textarea w-full"
                        value={formik.values.description}
                        onChange={formik.handleChange}
                    />
                </div>

                <div>
                    <label>Batch Mode <span className="text-danger">*</span></label>
                    <Select
                        options={modeOptions}
                        value={modeOptions.find(o => o.value === formik.values.mode)}
                        onChange={(val: any) => formik.setFieldValue("mode", val.value)}
                    />
                    {formik.errors.mode && formik.touched.mode && (
                        <div className="text-danger text-xs">{formik.errors.mode}</div>
                    )}
                </div>

                <div>
                    <label>Course <span className="text-danger">*</span></label>
                    <Select
                        options={courseOptions}
                        value={courseOptions.find(o => o.value === formik.values.course_id)}
                        onChange={(val: any) => {
                            formik.setFieldValue("course_id", val.value);
                            if (formik.values.start_date) {
                                calculateEndDate(formik.values.start_date, val.value);
                            }
                        }}
                    />
                    {formik.errors.course_id && formik.touched.course_id && (
                        <div className="text-danger text-xs">{formik.errors.course_id}</div>
                    )}
                </div>

                <div>
                    <label>Room <span className="text-danger">*</span></label>
                    <Select
                        options={roomOptions}
                        value={roomOptions.find(o => o.value === formik.values.room_id)}
                        onChange={(val: any) => formik.setFieldValue("room_id", val.value)}
                    />
                    {formik.errors.room_id && formik.touched.room_id && (
                        <div className="text-danger text-xs">{formik.errors.room_id}</div>
                    )}
                </div>

                <div>
                    <label>Enrollment Capacity <span className="text-danger">*</span></label>
                    <input
                        type="number"
                        name="capacity"
                        className="form-input w-full"
                        value={formik.values.capacity}
                        onChange={formik.handleChange}
                        onBlur={formik.handleBlur}
                    />
                    {formik.errors.capacity && formik.touched.capacity && (
                        <div className="text-danger text-xs">{formik.errors.capacity}</div>
                    )}
                </div>

                <div>
                    <label>Schedule Days <span className="text-danger">*</span></label>
                    <Select
                        options={scheduleOptions}
                        value={scheduleOptions.find(o => o.value === formik.values.schedule)}
                        onChange={(val: any) => formik.setFieldValue("schedule", val.value)}
                    />
                    {formik.errors.schedule && formik.touched.schedule && (
                        <div className="text-danger text-xs">{formik.errors.schedule}</div>
                    )}
                </div>

                <div>
                    <label>Start Date <span className="text-danger">*</span></label>
                    <Datepicker
                        value={formik.values.start_date}
                        onChange={(val) => {
                            if (!val || Array.isArray(val)) return;
                            const formattedDate = formatDate(val);
                            formik.setFieldValue("start_date", formattedDate);
                            if (formattedDate && formik.values.course_id) {
                                calculateEndDate(formattedDate, formik.values.course_id);
                            }
                        }}
                        placeholder="Pick start date"
                        // Disable dates based on schedule selection
                        disable={[(date: Date) => {
                            const dayOfWeek = date.getDay(); // 0 = Sunday, 6 = Saturday

                            if (formik.values.schedule === 'weekdays') {
                                // Disable weekends (Saturday = 6, Sunday = 0)
                                return dayOfWeek === 0 || dayOfWeek === 6;
                            } else if (formik.values.schedule === 'weekends') {
                                // Disable weekdays (Monday-Friday = 1-5)
                                return dayOfWeek >= 1 && dayOfWeek <= 5;
                            }

                            // If no schedule selected yet, allow all days
                            return false;
                        }]}
                        // Min date is today
                        minDate={new Date()}
                    />
                    {formik.errors.start_date && formik.touched.start_date && (
                        <div className="text-danger text-xs">{formik.errors.start_date}</div>
                    )}
                    {formik.values.schedule && (
                        <div className="text-xs text-gray-500 mt-1">
                            {formik.values.schedule === 'weekdays'
                                ? 'Available: Monday to Friday only'
                                : 'Available: Saturday and Sunday only'}
                        </div>
                    )}
                </div>

                <div>
                    <label>End Date <span className="text-danger">*</span></label>
                    <input
                        type="text"
                        className="form-input w-full bg-gray-100 cursor-not-allowed"
                        value={formik.values.end_date}
                        disabled={true}
                        placeholder="Auto-calculated based on course duration"
                    />
                    {formik.errors.end_date && formik.touched.end_date && (
                        <div className="text-danger text-xs">{formik.errors.end_date}</div>
                    )}
                    <div className="text-xs text-gray-500 mt-1">
                        End date is automatically calculated based on course duration
                    </div>
                </div>

                <div>
                    <label>Batch Start Time <span className="text-danger">*</span></label>
                    <Timepicker
                        value={formik.values.start_time}
                        onChange={(val) => formik.setFieldValue("start_time", val)}
                        placeholder="Start time"
                    />
                    {formik.errors.start_time && formik.touched.start_time && (
                        <div className="text-danger text-xs">{formik.errors.start_time}</div>
                    )}
                </div>

                <div>
                    <label>Batch End Time <span className="text-danger">*</span></label>
                    <Timepicker
                        value={formik.values.end_time}
                        onChange={(val) => formik.setFieldValue("end_time", val)}
                        placeholder="End time"
                    />
                    {formik.errors.end_time && formik.touched.end_time && (
                        <div className="text-danger text-xs">{formik.errors.end_time}</div>
                    )}
                </div>

                <div>
                    <label>Trainer <span className="text-danger">*</span></label>
                    <Select
                        options={trainerOptions}
                        value={trainerOptions.find(o => o.value === formik.values.trainer_id)}
                        onChange={(val: any) => formik.setFieldValue("trainer_id", val.value)}
                    />
                    {formik.errors.trainer_id && formik.touched.trainer_id && (
                        <div className="text-danger text-xs">{formik.errors.trainer_id}</div>
                    )}
                </div>

                <div>
                    <label>Co-Trainer <span className="text-danger">*</span></label>
                    <Select
                        options={trainerOptions}
                        value={trainerOptions.find(o => o.value === formik.values.co_trainer)}
                        onChange={(val: any) => formik.setFieldValue("co_trainer", val.value)}
                    />
                </div>

                <div>
                    <label>Support Staff <span className="text-danger">*</span></label>
                    <Select
                        options={staffOptions}
                        value={staffOptions.find(o => o.value === formik.values.support_staff)}
                        onChange={(val: any) => formik.setFieldValue("support_staff", val.value)}
                    />
                </div>

                {/* Availability conflicts */}
                {availabilityConflicts.length > 0 && (
                    <div className="md:col-span-2 mt-2 p-3 bg-red-50 border border-red-200 rounded-md">
                        <h4 className="text-red-800 font-semibold mb-2">Scheduling Conflicts:</h4>
                        {availabilityConflicts.map((conflict, index) => (
                            <div key={index} className="text-sm text-red-700 mb-1">
                                • {conflict.staff_name} is already assigned to batch "{conflict.conflicting_batch}"
                                on {conflict.conflicting_dates} at {conflict.conflicting_time}
                            </div>
                        ))}
                    </div>
                )}

                {isCheckingAvailability && (
                    <div className="md:col-span-2 mt-2 p-3 bg-blue-50 border border-blue-200 rounded-md">
                        <div className="flex items-center gap-2 text-blue-700">
                            <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-blue-700"></div>
                            <span>Checking staff availability...</span>
                        </div>
                    </div>
                )}
            </form>
        </Modal>
    );
};

export default AddBatch;
