import React, { useState, useEffect } from 'react';
import { Calendar, momentLocalizer, dateFnsLocalizer } from 'react-big-calendar';
import 'react-big-calendar/lib/css/react-big-calendar.css';
import AvailabilityForm from '../availability/AvailabilityForm';
import common from '../../src/helpers/common';

import { toast } from 'react-toastify';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import moment from 'moment';
import 'moment/locale/bg'; // Import Bulgarian locale
import { ArrowLeftCircleIcon } from '@heroicons/react/24/outline';

import { FaArrowLeft, FaArrowRight, FaRegCalendarAlt, FaRegListAlt, FaRegCalendarCheck } from 'react-icons/fa';
import { MdToday } from 'react-icons/md';

import { useSwipeable } from 'react-swipeable';
import axiosInstance from '../../src/axiosSecure';
import { set } from 'date-fns';

// Set moment to use the Bulgarian locale
moment.locale('bg');
const localizer = momentLocalizer(moment);
// Bulgarian translations for Calendar labels
const messages = {
    allDay: 'Цял ден',
    previous: 'Предишен',
    next: 'Следващ',
    today: 'Днес',
    month: 'Месец',
    week: 'Седмица',
    day: 'Ден',
    agenda: 'Дневен ред',
    date: 'Дата',
    time: 'Час',
    event: 'Събитие', // or 'Събитие' depending on context
    // Any other labels you want to translate...
};

const AvCalendar = ({ publisherId, events, selectedDate }) => {

    const [date, setDate] = useState(new Date());
    const [currentView, setCurrentView] = useState('month');
    const [evts, setEvents] = useState(events); // Existing events
    const [displayedEvents, setDisplayedEvents] = useState(evts); // Events to display in the calendar
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [selectedEvents, setSelectedEvents] = useState([]);
    const [visibleRange, setVisibleRange] = useState(() => {
        const start = new Date();
        start.setDate(1); // Set to the first day of the current month
        const end = new Date(start.getFullYear(), start.getMonth() + 1, 0); // Last day of the current month
        return { start, end };
    });



    // Update internal state when `events` prop changes
    useEffect(() => {
        //if we have isBySystem - set type to assignment
        let updatedEvents = events?.map(event => {
            if (event.isBySystem) {
                event.type = "assignment";
            }
            return event;
        });
        updatedEvents = events?.map(event => ({
            ...event,
            date: new Date(event.startTime).setHours(0, 0, 0, 0),
            startTime: new Date(event.startTime),
            endTime: event.endTime ? new Date(event.endTime) : undefined
        }));

        setEvents(updatedEvents);
        // Call any function here to process and set displayedEvents
        // based on the new events, if necessary
    }, [events]);

    const onRangeChange = (range) => {
        if (Array.isArray(range)) {
            // For week and day views, range is an array of dates
            setVisibleRange({ start: range[0], end: range[range.length - 1] });
        } else {
            // For month view, range is an object with start and end
            setVisibleRange(range);
        }
    };

    useEffect(() => {
        if (currentView === 'agenda') {
            const filtered = evts?.filter(event => event.type === "assignment");
            setDisplayedEvents(filtered);
        } else {
            // Function to generate weekly occurrences of an event
            const recurringEvents = evts?.filter(event => event.type !== "assignment" && (event.dayOfMonth === null || event.dayOfMonth === undefined)) || [];
            const occurrences = recurringEvents?.flatMap(event => generateOccurrences(event, visibleRange.start, visibleRange.end)) || [];
            const nonRecurringEvents = evts?.filter(event => event.dayOfMonth !== null) || [];

            setDisplayedEvents([...nonRecurringEvents, ...recurringEvents, ...occurrences]);
        }
        //setDisplayedEvents(evts);
    }, [visibleRange, evts, currentView]);

    const handlers = useSwipeable({
        onSwipedLeft: () => navigate('NEXT'),
        onSwipedRight: () => navigate('PREV'),
        preventDefaultTouchmoveEvent: true,
        trackMouse: true,
    });
    const navigate = (action) => {
        console.log('navigate', action);
        setDate((currentDate) => {
            const newDate = new Date(currentDate);
            if (action === 'NEXT') {
                newDate.setMonth(newDate.getMonth() + 1);
            } else if (action === 'PREV') {
                newDate.setMonth(newDate.getMonth() - 1);
            }
            return newDate;
        });
    };

    const generateOccurrences = (event, start, end) => {
        const occurrences = [];
        const eventStart = new Date(event.startTime);
        let current = new Date(event.startTime); // Assuming startTime has the start date

        // Determine the end date for the event series
        const seriesEndDate = event.endDate ? new Date(event.endDate) : end;
        seriesEndDate.setHours(23, 59, 59); // Set to the end of the day

        while (current <= seriesEndDate && current <= end) {
            // Check if the event should be repeated weekly or on a specific day of the month
            if (event.repeatWeekly && current.getDay() === eventStart.getDay()) {
                // For weekly recurring events
                addOccurrence(event, current, occurrences);
            } else if (event.dayOfMonth && current.getDate() === event.dayOfMonth) {
                // For specific day of month events
                addOccurrence(event, current, occurrences);
            }

            // Move to the next day
            current = new Date(current.setDate(current.getDate() + 1));
        }

        return occurrences;
    };

    // Helper function to add an occurrence
    const addOccurrence = (event, current, occurrences) => {
        // Skip the original event date

        const eventStart = new Date(event.startTime);
        const eventEnd = new Date(event.endTime);
        if (current.toDateString() !== eventStart.toDateString()) {
            const occurrence = {
                ...event,
                startTime: new Date(current.setHours(eventStart.getHours(), eventStart.getMinutes())),
                endTime: new Date(current.setHours(eventEnd.getHours(), eventEnd.getMinutes())),
                date: current,
                type: 'recurring'
            };
            occurrences.push(occurrence);
        }
    };

    // Define min and max times
    const minHour = 8;  // 8:00 AM
    const maxHour = 20; // 8:00 PM
    const minTime = new Date();
    minTime.setHours(minHour, 0, 0);
    const maxTime = new Date();
    maxTime.setHours(maxHour, 0, 0);
    const totalHours = maxHour - minHour;

    const handleSelect = ({ start, end }) => {
        const startdate = typeof start === 'string' ? new Date(start) : start;
        const enddate = typeof end === 'string' ? new Date(end) : end;

        if (!start || !end) return;
        if (startdate < new Date() || end < new Date() || startdate > end) return;

        // Check if start and end are on the same day
        if (startdate.toDateString() !== enddate.toDateString()) {
            end = common.setTimeHHmm(startdate, "23:59");
        }

        const startMinutes = common.getTimeInMinutes(start);
        const endMinutes = common.getTimeInMinutes(end);

        // Adjust start and end times to be within min and max hours
        if (startMinutes < common.getTimeInMinutes(common.setTimeHHmm(start, minHour))) {
            start = common.setTimeHHmm(start, minHour);
        }
        if (endMinutes > common.getTimeInMinutes(common.setTimeHHmm(end, maxHour))) {
            end = common.setTimeHHmm(end, maxHour);
        }

        setDate(start);

        // get exising events for the selected date
        const existingEvents = evts?.filter(event => (event.publisher?.id || event.publisherId) === publisherId && new Date(event.date).toDateString() === startdate.toDateString());
        // const existingEvents = evts?.filter(event => {
        //     return event.publisherId === publisherId &&
        //         new Date(event.startTime).getFullYear() === start.getFullYear() &&
        //         new Date(event.startTime).getMonth() === start.getMonth() &&
        //         new Date(event.startTime).getDate() === start.getDate();
        // });
        console.log("handleSelect: " + existingEvents);
        setSelectedEvents(existingEvents);

        // setSelectedEvent({
        //     date: start,
        //     startTime: start,
        //     endTime: end,
        //     dayOfMonth: start.getDate(),
        //     isActive: true,
        //     publisherId: publisherId,
        //     // Add any other initial values needed
        //     //set dayOfMonth to null, so that we repeat the availability every week
        //     dayOfMonth: null,

        // });
        setIsModalOpen(true);
    };

    const handleEventClick = (event) => {
        if (event.type === "assignment") return;
        handleSelect({ start: event.startTime, end: event.endTime });
        // Handle event click
        // const eventForEditing = {
        //     ...event,
        //     startTime: new Date(event.startTime),
        //     endTime: new Date(event.endTime),
        //     publisherId: event.publisherId || event.publisher?.connect?.id,
        //     repeatWeekly: event.repeatWeekly || false,
        // };
        // //strip title, start, end and allDay properties
        // delete eventForEditing.title;
        // delete eventForEditing.start;
        // delete eventForEditing.end;
        // delete eventForEditing.type;
        // delete eventForEditing.publisher
        // console.log("handleEventClick: " + eventForEditing);
        // setSelectedEvents([eventForEditing]);
        // setIsModalOpen(true);

    };

    const handleDialogClose = async (dialogEvent) => {
        setIsModalOpen(false);
        if (dialogEvent === null || dialogEvent === undefined) {
        } else {
            let e = await axiosInstance.get(`/api/?action=getCalendarEvents&publisherId=${publisherId}`);
            var newEvents = e.data;
            // set start and end to Date objects for all events. Fix for the calendar component
            newEvents.forEach(event => {
                event.startTime = new Date(event.startTime);
                event.endTime = new Date(event.endTime);

            });
            setEvents(newEvents);

        }

        console.log("handleSave: ", dialogEvent);
    };

    const handleCancel = () => {
        setIsModalOpen(false);
    };

    const EventWrapper = ({ event, style }) => {
        const [isHovered, setIsHovered] = useState(false);
        let eventStyle = {
            ...style
        };
        const handleMouseEnter = () => setIsHovered(true);
        const handleMouseLeave = () => setIsHovered(false);
        if (currentView !== 'agenda') {
            //if event.type is availability show in blue. if it is schedule - green if confirmed, yellow if not confirmed
            //if event is not active - show in gray
            let bgColorClass = 'bg-gray-500'; // Default color for inactive events
            var bgColor = event.isActive ? "" : "bg-gray-500";
            //ToDo: fix this. maybe we're missing some properties
            // if (event.isFromPreviousMonth) {
            //     //    set opacity to 0.5 
            //     bgColor = "bg-orange-500";
            // }
            if (event.type === "assignment") {
                bgColor = event.isBySystem ? "bg-red-500" : (event.isConfirmed ? "bg-green-500" : "bg-yellow-500");

                //event.title = event.publisher.name; //ToDo: add other publishers names
                //event.title = common.getTimeFomatted(event.startTime) + " - " + common.getTimeFomatted(event.endTime);
            } else {
                if (event.start !== undefined && event.end !== undefined && event.startTime !== null && event.endTime !== null) {
                    try {
                        if (event.type === "recurring") {
                            //bgColor = "bg-blue-300";
                            event.title = common.getTimeFomatted(event.startTime) + " - " + common.getTimeFomatted(event.endTime);
                        }
                        else {
                            event.title = common.getTimeFomatted(event.startTime) + " - " + common.getTimeFomatted(event.endTime);
                        }
                    }
                    catch (err) {
                        event.title = event.startTime + " - " + event.endTime;
                        console.log("Error in EventWrapper: " + err);
                    }

                }
            }

            eventStyle = {
                ...style,
                // backgroundColor: bgColorClass,
                //height: "50px",
                //color: 'white',
                //if (event.isFromPreviousAssignment) { set opacity to 0.5 }
                // opacity: event.isFromPreviousMonth ? 0.5 : 1,
                whiteSpace: 'normal', // Allow the text to wrap to the next line
                overflow: 'hidden',  // Hide overflowed content
                textOverflow: 'ellipsis' // Add ellipsis to text that's too long to fit
            };


        }
        const onDelete = (event) => {
            // Remove the event from the calendar
            setEvents(currentEvents => currentEvents.filter(e => e.id !== event.id));
        };

        const onConfirm = (event) => {
            console.log("onConfirm: " + event.id);
            toast.info("Потвърдено!", { autoClose: 2000 });
            // Update the event data
            event.isConfirmed = true;
            event.isBySystem = false;
            // Update the events array by first removing the old event and then adding the updated one
            setEvents(currentEvents => {
                const filteredEvents = currentEvents.filter(e => e.id !== event.id);
                return [...filteredEvents, event];
            });
            //store the updated event in the database
            var assignment = {
                isConfirmed: true,
                isBySystem: false
            };
            axiosInstance.put('/api/data/assignments/' + event.id, assignment)
                .then((response) => {
                    console.log(response);
                })
                .catch((error) => {
                    console.log(error);
                });
        };
        return (
            <div style={eventStyle} className={bgColor + " relative"}
                onMouseEnter={handleMouseEnter}
                onMouseLeave={handleMouseLeave} >
                {event.title}
                {isHovered && event.type == "assignment" && (event.status == "pending" || event.status == undefined)
                    && (
                        <div className="absolute top-1 left-0 right-0 flex justify-between px-1">
                            {/* Delete Icon */}
                            {/* <span
                                className="disabled cursor-pointer rounded-full bg-red-500 text-white flex items-center justify-center"
                                style={{ width: '24px', height: '24px' }} // Adjust the size as needed
                                onClick={() => onDelete(event)}
                            >
                                ✕
                            </span> */}

                            {/* Confirm Icon */}
                            {/* {!event.isConfirmed && (
                                <span
                                    className=" cursor-pointer rounded-full bg-green-500 text-white flex items-center justify-center"
                                    style={{ width: '24px', height: '24px' }} // Adjust the size as needed
                                    onClick={() => onConfirm(event)}
                                >
                                    ✓
                                </span>
                            )} */}
                        </div>
                    )}
            </div>
        );
    };

    const eventStyleGetter = (event, start, end, isSelected) => {

        //console.log("eventStyleGetter: " + event);
        let backgroundColor = '#3174ad';         // default color for calendar events - #3174ad
        if (currentView === 'agenda') {
            return { style: {} }
        }
        if (event.type === "assignment") {
            //event.title = event.publisher.name; //ToDo: add other publishers names
        }
        if (event.type === "availability") {

        }
        if (event.isFromPreviousAssignment) { //ToDo: does it work?
            // orange-500 from Tailwind CSS
            backgroundColor = '#f56565';
        }
        if (event.isActive) {
            switch (event.type) {
                case 'assignment':
                    backgroundColor = event.isConfirmed ? '#48bb78' : '#f6e05e'; // green-500 and yellow-300 from Tailwind CSS
                    break;
                case 'recurring':
                    backgroundColor = '#63b3ed'; // blue-300 from Tailwind CSS
                    break;
                default: // availability
                    //backgroundColor = '#a0aec0'; // gray-400 from Tailwind CSS
                    break;
            }
        } else {
            backgroundColor = '#a0aec0'; // Default color for inactive events
        }

        return {
            style: {
                backgroundColor,
                opacity: 0.8,
                color: 'white',
                border: '0px',
                display: 'block',
            }
        };
    }

    // Custom Toolbar Component

    const CustomToolbar = ({ onNavigate, label, onView, view }) => {
        return (
            <div className="rbc-toolbar">
                <span className="rbc-btn-group">
                    <button type="button" onClick={() => onNavigate('PREV')}>
                        <FaArrowLeft className="icon-large" />
                    </button>
                    <button type="button" onClick={() => onNavigate('TODAY')}>
                        <MdToday className="icon-large" />
                    </button>
                    <button type="button" onClick={() => onNavigate('NEXT')}>
                        <FaArrowRight className="icon-large" />
                    </button>
                </span>
                <span className="rbc-toolbar-label">{label}</span>
                <span className="rbc-btn-group">
                    <button type="button" onClick={() => onView('month')} className={view === 'month' ? 'rbc-active' : ''}>
                        <FaRegCalendarAlt className="icon-large" />
                    </button>
                    <button type="button" onClick={() => onView('week')} className={view === 'week' ? 'rbc-active' : ''}>
                        <FaRegListAlt className="icon-large" />
                    </button>
                    <button type="button" onClick={() => onView('agenda')} className={view === 'agenda' ? 'rbc-active' : ''}>
                        <FaRegCalendarCheck className="icon-large" />
                    </button>
                    {/* Add more view buttons as needed */}
                </span>
            </div>
        );
    };

    return (
        <> <div  {...handlers} className="flex flex-col"
        >
            {/* достъпности на {publisherId} */}
            <ToastContainer position="top-center" style={{ zIndex: 9999 }} />
        </div>
            <Calendar
                localizer={localizer}
                events={displayedEvents}
                startAccessor="startTime"
                endAccessor="endTime"
                selectable={true}
                onSelectSlot={handleSelect}
                onSelectEvent={handleEventClick}
                style={{ height: '100%', width: '100%' }}
                min={minTime} // Set minimum time
                max={maxTime} // Set maximum time
                messages={messages}
                view={currentView}
                views={['month', 'week', 'agenda']}
                onView={view => setCurrentView(view)}
                onRangeChange={onRangeChange}
                components={{
                    event: EventWrapper,
                    toolbar: CustomToolbar,
                    // ... other custom components
                }}
                eventPropGetter={(eventStyleGetter)}
                date={date}
                onNavigate={setDate}
                className="rounded-lg shadow-lg"
            />
            {isModalOpen && (
                <div className="fixed inset-0 flex items-center justify-center z-50">
                    <div className="modal-content">
                        <AvailabilityForm
                            publisherId={publisherId}
                            existingItems={selectedEvents}
                            date={date}
                            onDone={handleDialogClose}
                            inline={true}
                        // Pass other props as needed
                        />
                    </div>
                    <div className="fixed inset-0 bg-black opacity-50" onClick={handleCancel}></div>
                </div>
            )}
        </>
    );
};

export default AvCalendar;
