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, useRef } from "react";

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

interface CourseOption {
    value: string;
    label: string;
    duration: string;
    durationMonths: number;
    durationHours: number;
}

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

const EditBatch = ({ open, onClose, onSave, data }: 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 [loading, setLoading] = useState(false);
    const [initialLoadComplete, setInitialLoadComplete] = useState(false);
    const [originalStaffIds, setOriginalStaffIds] = useState<string[]>([]);

    // Use a ref to track if initial load is done
    const initialLoadRef = useRef(false);

    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 duration info from string
    const extractDurationInfo = (duration: any) => {
        if (!duration) return { months: 0, hours: 0 };

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

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

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

        if (months === 0 && hours === 0) {
            const numMatch = durationStr.match(/(\d+)/);
            if (numMatch) {
                const num = parseInt(numMatch[1]);
                if (num > 12) hours = num;
                else months = num;
            }
        }

        return { months, hours };
    };

    // Check if date is valid for schedule
    const isDateValidForSchedule = (date: Date, schedule: string): boolean => {
        if (!schedule) return true;
        const dayOfWeek = date.getDay();
        if (schedule === 'weekdays') return dayOfWeek >= 1 && dayOfWeek <= 5;
        if (schedule === 'weekends') return dayOfWeek === 0 || dayOfWeek === 6;
        return true;
    };

    // Calculate end date
    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);

        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,
                exclude_batch_id: data?.id
            });

            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]);

    // Helper to extract ID from nested object or string
    const extractId = (value: any): string => {
        if (!value) return "";
        if (typeof value === 'object' && value !== null) {
            return String(value.id || "");
        }
        return String(value);
    };

    // Helper to format date from API
    const formatDateFromApi = (dateStr: string): string => {
        if (!dateStr) return "";
        if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) return dateStr;
        try {
            const date = new Date(dateStr);
            return date.toISOString().split('T')[0];
        } catch {
            return dateStr;
        }
    };

    // Helper to format time from API
    const formatTimeFromApi = (timeStr: string): string => {
        if (!timeStr) return "";
        return timeStr.substring(0, 5);
    };

    const formatDate = (date: Date) => {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, "0");
        const day = String(date.getDate()).padStart(2, "0");
        return `${year}-${month}-${day}`;
    };

    // Handle date selection
    const handleDateSelection = (date: Date) => {
        if (formik.values.schedule && !isDateValidForSchedule(date, formik.values.schedule)) {
            const scheduleType = formik.values.schedule === 'weekdays' ? 'Monday-Friday' : 'Saturday-Sunday';
            toast.warning(`Please select a date that falls on ${scheduleType}`);
            return;
        }

        const formattedDate = formatDate(date);
        formik.setFieldValue("start_date", formattedDate);

        if (formattedDate && formik.values.course_id) {
            calculateEndDate(formattedDate, formik.values.course_id);
        }
    };

    // ==========================================
    // FORMIK - MUST BE DECLARED BEFORE EFFECTS THAT USE IT
    // ==========================================
    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({
        enableReinitialize: true,
        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) => {
            // Only check availability if staff actually changed
            if (haveStaffIdsChanged()) {
                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 updating');
                    return;
                }
            }

            try {
                const response = await api.put(`/batch/update/${data.id}`, {
                    ...values,
                    regenerate_schedule: true
                });

                if (response.data.status) {
                    toast.success('Batch updated successfully with new schedule!');
                    onSave(response.data.data);
                    onClose();
                }
            } catch (error: any) {
                console.error('Error updating batch:', error);
                toast.error(error.response?.data?.message || 'Failed to update batch');
            }
        },
    });

    // ==========================================
    // EFFECTS - NOW AFTER FORMIK DECLARATION
    // ==========================================

    // Fetch batch details for editing
    useEffect(() => {
        const fetchBatchDetails = async () => {
            if (!data?.id || !open) return;

            setLoading(true);
            initialLoadRef.current = false;
            setInitialLoadComplete(false);

            try {
                const response = await api.get(`/batch/edit/${data.id}`);

                if (response.data.status === true) {
                    const batchData = response.data.data;

                    const formValues = {
                        batch_name: batchData.batch_name || "",
                        description: batchData.description || "",
                        start_date: formatDateFromApi(batchData.start_date),
                        end_date: formatDateFromApi(batchData.end_date),
                        start_time: formatTimeFromApi(batchData.start_time),
                        end_time: formatTimeFromApi(batchData.end_time),
                        mode: batchData.batch_mode || "",
                        schedule: batchData.schedule_days || "",
                        capacity: batchData.capacity || "",
                        course_id: batchData.course_id || "",
                        room_id: batchData.room_id || "",
                        trainer_id: extractId(batchData.trainer_id || batchData.trainer),
                        co_trainer: extractId(batchData.co_trainer),
                        support_staff: extractId(batchData.support_staff),
                    };

                    setOriginalStaffIds([
                        formValues.trainer_id,
                        formValues.co_trainer,
                        formValues.support_staff
                    ].filter(id => id && id !== ""));

                    formik.setValues(formValues);

                    if (batchData.course_id) {
                        fetchStaffByCourseSkills(String(batchData.course_id));
                    }
                }
            } catch (error) {
                console.error('Error fetching batch details:', error);
                toast.error('Failed to load batch details');
            } finally {
                setLoading(false);
                // Mark initial load complete after delay
                setTimeout(() => {
                    initialLoadRef.current = true;
                    setInitialLoadComplete(true);
                }, 1500);
            }
        };

        fetchBatchDetails();
    }, [data?.id, open]);

    // Check if staff IDs have changed
    const haveStaffIdsChanged = (): boolean => {
        const currentIds = [
            formik.values.trainer_id,
            formik.values.co_trainer,
            formik.values.support_staff
        ].filter(id => id && id !== "");

        if (currentIds.length !== originalStaffIds.length) return true;

        const sortedCurrent = [...currentIds].sort();
        const sortedOriginal = [...originalStaffIds].sort();

        return sortedCurrent.some((id, index) => id !== sortedOriginal[index]);
    };

    // 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]);

    // Reset date when schedule changes
    useEffect(() => {
        if (formik.values.start_date && formik.values.schedule) {
            const currentDate = new Date(formik.values.start_date);
            if (!isDateValidForSchedule(currentDate, formik.values.schedule)) {
                toast.info('Selected date is not valid for the chosen schedule. Please select a new date.');
                formik.setFieldValue("start_date", "");
                formik.setFieldValue("end_date", "");
            }
        }
    }, [formik.values.schedule]);

    // Check availability on changes - ONLY after initial load
    useEffect(() => {
        // Skip if still loading initially
        if (!initialLoadComplete || !initialLoadRef.current) {
            return;
        }

        // Skip if no changes from original
        if (!haveStaffIdsChanged()) {
            setAvailabilityConflicts([]);
            return;
        }

        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);
            }
        }, 800);

        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,
        initialLoadComplete
    ]);

   return (
        <Modal
            open={open}
            onClose={onClose}
            title="Update 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 || loading}
                    >
                        {isCheckingAvailability ? 'Checking Availability...' : 'Update Batch & Regenerate Schedule'}
                    </button>
                </>
            }
        >
            {loading ? (
                <div className="flex justify-center items-center py-12">
                    <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
                    <span className="ml-3">Loading batch details...</span>
                </div>
            ) : (
                <form className="grid grid-cols-1 md:grid-cols-2 gap-4">
                    {/* All form fields remain the same as your current code */}
                    <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) => {
                                console.log('Datepicker onChange raw value:', val);

                                if (!val) return;

                                if (Array.isArray(val)) {
                                    const date = val[0];
                                    if (!date) return;
                                    handleDateSelection(date);
                                    return;
                                }

                                handleDateSelection(val);
                            }}
                            placeholder="Pick start date"
                            minDate={new Date()}
                            // Disable dates based on schedule
                            disable={[(date: Date) => {
                                const schedule = formik.values.schedule;
                                if (!schedule) return false; // allow all dates

                                const day = date.getDay();

                                if (schedule === 'weekdays') {
                                    return day === 0 || day === 6; // disable weekends
                                }

                                if (schedule === 'weekends') {
                                    return day >= 1 && day <= 5; // disable weekdays
                                }

                                return false;
                            }]}
                        />
                        {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 mt-1 px-2 py-1 rounded inline-block ${
                                formik.values.schedule === 'weekdays'
                                    ? 'bg-blue-50 text-blue-700'
                                    : 'bg-orange-50 text-orange-700'
                            }`}>
                                {formik.values.schedule === 'weekdays'
                                    ? '📅 Available: Monday - Friday (Weekdays)'
                                    : '📅 Available: Saturday & Sunday (Weekends)'}
                            </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 ?? undefined}
                            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 ?? undefined}
                            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 => String(o.value) === String(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 => String(o.value) === String(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 => String(o.value) === String(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 EditBatch;
