import axiosInstance from '../../src/axiosSecure';
import { useEffect, useState, useCallback, use } from "react";
import toast from "react-hot-toast";
import { useRouter } from "next/router";
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3';
import bg from 'date-fns/locale/bg';
import { bgBG } from '../x-date-pickers/locales/bgBG';
import { ToastContainer } from 'react-toastify';
const common = require('src/helpers/common');
//todo import Availability type from prisma schema
import { isBefore, addMinutes, isAfter, isEqual, set, getHours, getMinutes, getSeconds } from 'date-fns'; //ToDo obsolete?
import { stat } from 'fs';

const { DateTime, FixedOffsetZone } = require('luxon');



const fetchConfig = async () => {
  const config = await import('../../config.json');
  return config.default;
};

export default function AvailabilityForm({ publisherId, existingItems, inline, onDone, date, cartEvent, datePicker = false, lockedBeforeDate }) {

  const router = useRouter();
  const urls = {
    apiUrl: "/api/data/availabilities/",
    indexUrl: "/cart/availabilities"
  };

  const id = parseInt(router.query.id);

  const originalAvailabilities = existingItems || [];

  const [editMode, setEditMode] = useState(existingItems.length > 0);
  const [publisher, setPublisher] = useState({ id: publisherId });
  const [day, setDay] = useState(new Date(date));
  const [canUpdate, setCanUpdate] = useState(true);


  const [timeSlots, setTimeSlots] = useState([]);
  const [availabilities, setAvailabilities] = useState(existingItems && existingItems.length > 0 ? existingItems : [{
    publisherId: publisher.id,
    name: "Нов",
    dayofweek: "Monday",
    dayOfMonth: null,
    // startTime: "08:00",
    // endTime: "20:00",
    isActive: true,
    repeatWeekly: false,
    endDate: null,
    isFirst: false,
    isLast: false,
  }]);

  const [doRepeat, setDoRepeat] = useState(existingItems && existingItems.length > 0 ? existingItems[0].repeatWeekly : false);
  const [repeatFrequency, setRepeatFrequency] = useState(1);
  const [repeatUntil, setRepeatUntil] = useState(null);

  const [isInline, setInline] = useState(inline || false);
  const [config, setConfig] = useState(null);
  useEffect(() => {
    fetchConfig().then(config => {
      console.log("UI config: ", config);
      setConfig(config);
    });
  }, []);


  // get cart event or set default time for Sofia timezone
  // const minTime = cartEvent?.startTime || DateTime.now().set({ hour: 8, minute: 0, zone: 'Europe/Sofia' }).toJSDate();
  // const maxTime = cartEvent?.endTime || DateTime.now().set({ hour: 20, minute: 0, zone: 'Europe/Sofia' }).toJSDate();
  const d = DateTime.fromJSDate(day).setZone('Europe/Sofia', { keepLocalTime: true });
  const minTime = d.set({ hour: 9, minute: 0 }).toJSDate();
  const maxTime = d.set({ hour: 19, minute: 30 }).toJSDate();

  useEffect(() => {
    setTimeSlots(generateTimeSlots(new Date(minTime), new Date(maxTime), cartEvent?.shiftDuration || 90, availabilities));
    console.log("AvailabilityForm: minTime: " + common.getTimeFormatted(minTime) + ", maxTime: " + common.getTimeFormatted(maxTime), ", " + cartEvent?.shiftDuration || 90 + " min. shifts", cartEvent ? "cartEvent" : "cartEvent MISSING!!!");
  }, []);


  const fetchItemFromDB = async () => {
    if (existingItems.length == 0 && id) {
      try {
        const response = await axiosInstance.get(`/api/data/availabilities/${id}`);
        setAvailabilities([response.data]);
        setEditMode(true);
        setDoRepeat(response.data.repeatWeekly);
      } catch (error) {
        console.error(error);
        toast.error("Error fetching availability data.");
      }
    }
  };

  useEffect(() => {
    fetchItemFromDB();
  }, [router.query.id]);


  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const groupedTimeSlots = mergeCheckedTimeSlots(timeSlots);
      let avs = availabilities.filter(av => av.type !== "assignment");
      // Determine if we need to delete and recreate, or just update
      let shouldRecreate = avs.length > 0 && avs.length !== groupedTimeSlots.length || avs.some(av => !av.id);
      shouldRecreate = shouldRecreate || (avs.length == 0 && availabilities.length > 0);
      //create availability if we open a form with assignment without availability 

      if (shouldRecreate) {
        // Delete existing availabilities if they have an ID
        console.log("Recreating availabilities");
        await Promise.all(avs.filter(av => av.id).map(av => axiosInstance.delete(`${urls.apiUrl}${av.id}`)));

        // Create new availabilities
        avs = await Promise.all(groupedTimeSlots.map(async group => {
          const newAvailability = createAvailabilityFromGroup(group, publisher.id);
          const response = await axiosInstance.post(urls.apiUrl, newAvailability);
          return response.data;  // Assuming the new availability is returned
        }));

        setAvailabilities(avs);
      } else {
        // Update existing availabilities
        console.log("Updating existing availabilities");
        avs = await Promise.all(avs.map(async (availability, index) => {
          const group = groupedTimeSlots[index];
          const id = availability.id;
          const updatedAvailability = updateAvailabilityFromGroup(availability, group);
          delete updatedAvailability.id;
          //delete updatedAvailability.type;
          delete updatedAvailability.publisherId;
          delete updatedAvailability.title;
          delete updatedAvailability.date;
          updatedAvailability.publisher = { connect: { id: publisher.id } };
          await axiosInstance.put(`${urls.apiUrl}${id}`, updatedAvailability);
          return updatedAvailability;
        }));

        setAvailabilities(avs);
      }


      // Handle repetition logic
      // const parentAvailabilityId = avs[0].id;
      // originalAvailabilities.forEach(async av => {
      //   if (av.repeatWeekly && av.startTime < lockedBeforeDate) {
      //     const newDate = av.startTime;
      //     while (newDate < lockedBeforeDate) {
      //       const newAvailability = {
      //         ...av,
      //         startTime: newDate,
      //         parentAvailability: { connect: { id: parentAvailabilityId } },
      //         publisher: { connect: { id: publisher.id } },
      //         dateOfEntry: new Date(),
      //         type: "OneTime"
      //       };

      //       delete newAvailability.id;
      //       delete newAvailability.title;
      //       delete newAvailability.date;
      //       delete newAvailability.publisherId

      //       await axiosInstance.post(urls.apiUrl, newAvailability);
      //       newDate.setDate(newDate.getDate() + 7); // Repeat weekly
      //     }
      //   }
      //   console.log("Updated availability: ", av)
      // }
      // );

      handleCompletion({ updated: true });
    } catch (error) {
      alert("Нещо се обърка. Моля, опитайте отново по-късно.");
      //   toast.error("Нещо се обърка. Моля, опитайте отново по-късно.");
      //   console.error(error.message);
      //   try {
      //     const { data: session, status } = useSession();
      //     const userId = session.user.id;
      //     axiosInstance.post('/log', { message: error.message, userId: userId });
      //   }
      //   catch (err) {
      //     console.error("Error logging error: ", err);
      //   }
    }
  };


  function mergeCheckedTimeSlots(timeSlots) {
    const selectedSlots = timeSlots.filter(slot => slot.isChecked);
    // Sort the selected intervals by start time
    const sortedSlots = [...selectedSlots].sort((a, b) => a.startTime - b.startTime);

    // Group continuous slots
    const groupedIntervals = [];
    let currentGroup = [sortedSlots[0]];

    for (let i = 1; i < sortedSlots.length; i++) {
      const previousSlot = currentGroup[currentGroup.length - 1];
      const currentSlot = sortedSlots[i];
      // Calculate the difference in hours between slots
      const difference = (currentSlot.startTime - previousSlot.endTime) / (60 * 60 * 1000);

      // Assuming each slot represents an exact match to the increment (1.5 hours), we group them
      if (difference === 0) {
        currentGroup.push(currentSlot);
      } else {
        groupedIntervals.push(currentGroup);
        currentGroup = [currentSlot];
      }
    }
    // Don't forget the last group
    if (currentGroup.length > 0) {
      groupedIntervals.push(currentGroup);
    }
    return groupedIntervals;
  }

  // Common function to set shared properties
  function setSharedAvailabilityProperties(availability, group, timeSlots) {
    const d = DateTime.fromJSDate(day).setZone('Europe/Sofia', { keepLocalTime: true });
    console.log("day: " + d.toISODate());
    let startTime = common.setTime(d, group[0].startTime).toJSDate();
    let endTime = common.setTime(d, group[group.length - 1].endTime).toJSDate();

    availability.startTime = startTime;
    availability.endTime = endTime;
    availability.name = common.getTimeFormatted(group[0].startTime) + "-" + common.getTimeFormatted(group[group.length - 1].endTime);

    availability.isWithTransportIn = group[0].isFirst && timeSlots[0].isWithTransport;
    availability.isWithTransportOut = group[group.length - 1].isLast && timeSlots[timeSlots.length - 1].isWithTransport;

    // Adjustments for repeating settings
    if (doRepeat) {
      availability.repeatWeekly = true;
      availability.type = "Weekly"
      availability.dayOfMonth = null;
      availability.endDate = repeatUntil;
    } else {
      availability.type = "OneTime"
      availability.repeatWeekly = false;
      availability.dayOfMonth = availability.startTime.getDate();
      availability.endDate = null;
    }
    availability.isFromPreviousMonth = false;
    availability.dateOfEntry = new Date();
  }

  function createAvailabilityFromGroup(group, publisherId) {
    let availability = {
      publisherId: publisherId,
      dayofweek: common.getDayOfWeekNameEnEnumForDate(day),
    };

    setSharedAvailabilityProperties(availability, group, timeSlots);

    return availability;
  }

  function updateAvailabilityFromGroup(availability, group) {
    setSharedAvailabilityProperties(availability, group, timeSlots);

    delete availability.weekOfMonth;
    if (doRepeat) {
      availability.weekOfMonth = 0;
    }
    if (availability.parentAvailabilityId) {
      availability.parentAvailability = { connect: { id: parentAvailabilityId } };
    }
    delete availability.parentAvailabilityId;

    return availability;
  }



  const handleDelete = async (e) => {
    e.preventDefault();
    try {
      let avs = availabilities.filter(av => av.type !== "assignment");
      const deletePromises = avs.map(async (availability) => {
        if (availability.id) {
          // console.log("deleting publisher id = ", router.query.id, "; url=" + urls.apiUrl + router.query.id);
          await axiosInstance.delete(urls.apiUrl + availability.id);
        }
      });
      await Promise.all(deletePromises);
      toast.success("Записът изтрит", {
        position: "bottom-center",
      });
      if (handleCompletion) {
        handleCompletion({ deleted: true });
      }
    } catch (error) {
      //alert("Нещо се обърка при изтриването. Моля, опитайте отново или се свържете с нас");
      console.log(JSON.stringify(error));
      toast.error(error.response?.data?.message || "An error occurred");
      fetchItemFromDB();
    }
  };

  const handleCompletion = async (result) => {
    console.log("AvailabilityForm: handleCompletion");
    if (isInline) {
      if (onDone) {
        onDone(result);
      }
    } else {
      router.push(urls.indexUrl);
    }
  }

  // console.log("AvailabilityForm: publisherId: " + publisher.id + ", id: " + availabilit .id, ", inline: " + isInline);
  //ToDo: this is examplary function to be used in the future. replace all date/time related functions with this one
  const generateTimeSlots = (start, end, increment, items) => {
    const slots = [];
    let currentTime = start;
    while (isBefore(currentTime, end)) {
      let slotStart = currentTime;
      let slotEnd = addMinutes(currentTime, increment);

      const isChecked = items.some(item => {
        return item.startTime && item.endTime &&
          common.isTimeBetween(item.startTime, item.endTime, slotStart) &&
          common.isTimeBetween(item.startTime, item.endTime, slotEnd);
      });

      slots.push({ startTime: slotStart, endTime: slotEnd, isChecked: isChecked, });
      currentTime = addMinutes(currentTime, increment);
    }

    if (slots.length > 0 && items?.length > 0) {
      slots[0].isFirst = true;
      slots[slots.length - 1].isLast = true;
      slots[0].isWithTransport = items[0]?.isWithTransportIn;
      slots[slots.length - 1].isWithTransport = items[items.length - 1]?.isWithTransportOut;
    }

    return slots;
  };

  const TimeSlotCheckboxes = ({ slots, setSlots, items: [] }) => {
    const [allDay, setAllDay] = useState(slots.every(slot => slot.isChecked));
    const handleAllDayChange = (e) => {
      const updatedSlots = slots.map(slot => ({
        ...slot,
        isChecked: e.target.checked,
      }));
      setSlots(updatedSlots);
      setAllDay(e.target.checked)
      // setCanUpdate(slots.some(slot => slot.isChecked));
      const anyChecked = updatedSlots.some(slot => slot.isChecked);
      setCanUpdate(anyChecked);
      console.log("handleAllDayChange: allDay: " + allDay + ", updatedSlots: " + JSON.stringify(updatedSlots));
    };
    useEffect(() => {
      console.log("allDay updated to: ", allDay);
      const updatedSlots = slots.map(slot => ({
        ...slot,
        isChecked: allDay
      }));
      //setSlots(updatedSlots);
    }, [allDay]);

    const handleSlotCheckedChange = (changedSlot) => {
      const updatedSlots = slots.map(slot => {
        if (slot.startTime === changedSlot.startTime && slot.endTime === changedSlot.endTime) {
          return { ...slot, isChecked: !slot.isChecked };
        }
        return slot;
      });
      // If slot is either first or last and it's being unchecked, also uncheck and disable transport
      if ((changedSlot.isFirst || changedSlot.isLast) && !changedSlot.isChecked) {
        changedSlot.isWithTransport = false;
      }
      //if no slots are checked, disable Update button
      const anyChecked = updatedSlots.some(slot => slot.isChecked);
      setCanUpdate(anyChecked);

      setSlots(updatedSlots);
    };

    const handleTransportChange = (changedSlot) => {
      const updatedSlots = slots.map(slot => {
        if (slot.startTime === changedSlot.startTime && slot.endTime === changedSlot.endTime) {
          return { ...slot, isWithTransport: !slot.isWithTransport };
        }
        return slot;
      });
      setSlots(updatedSlots);
    };


    return (
      <>
        <label className="checkbox-container flex items-center mb-2">
          <input type="checkbox" checked={allDay} onChange={e => handleAllDayChange(e)} className="form-checkbox h-5 w-5 text-gray-600 mx-2" />
          Цял ден
          <span className="checkmark"></span>
        </label>
        {slots.map((slot, index) => {
          const slotLabel = `${common.getTimeFormatted(slot.startTime)} до ${common.getTimeFormatted(slot.endTime)}`;
          slot.transportNeeded = slot.isFirst || slot.isLast;
          // Determine if the current slot is the first or the last

          return (
            <div key={index} className="mb-1 flex justify-between items-center">
              <label className={`checkbox-container flex items-center mb-2 `}>
                <input type="checkbox" checked={slot.isChecked || allDay} onChange={() => handleSlotCheckedChange(slot)}

                  className="form-checkbox h-5 w-5 text-gray-600 mx-2" />
                {slotLabel}
                <span className="checkmark"></span>
              </label>

              {/* Conditionally render transport checkbox based on slot being first or last */}
              {slot.transportNeeded && (
                <label className={`checkbox-container flex items-center ${(!slot.isChecked) ? 'opacity-50' : ''}`}>
                  <input type="checkbox"
                    className="form-checkbox h-5 w-5 text-gray-600 mx-2"
                    checked={slot.isWithTransport}
                    disabled={!slot.isChecked}
                    // disabled={!slot.isChecked && slot.isFirst}
                    onChange={() => handleTransportChange(slot)} />
                  {slot.isFirst ? 'Вземане' : 'Връщане'}
                  <span className="checkmark"></span>
                </label>
              )}
            </div>
          );
        })}
      </>
    );
  };

  return (
    <div className="w-full">
      <ToastContainer></ToastContainer>
      <form id="formAv" className="form p-5 bg-white shadow-md rounded-lg" onSubmit={handleSubmit}>
        <h3 className="text-xl font-semibold mb-5 text-gray-800 border-b pb-2">
          {editMode ? "Редактирай" : "Нова"} възможност: {common.getDateFormattedShort(new Date(day))}
        </h3>

        <LocalizationProvider dateAdapter={AdapterDateFns} localeText={bgBG} adapterLocale={bg}>
          {datePicker && (
            <div className="mb-2">
              <DatePicker label="Изберете дата" value={day} onChange={setDay} />
            </div>
          )}
          <div className="mb-2">
            <label className="checkbox-container">
              <input type="checkbox" checked={doRepeat} className="form-checkbox h-5 w-5 text-gray-600 mx-2"
                onChange={(e) => setDoRepeat(e.target.checked)} />
              Повтаряй всяка {' '}
              {/* {repeatWeekly && (
                <select
                  style={{
                    appearance: 'none',
                    MozAppearance: 'none',
                    WebkitAppearance: 'none',
                    border: 'black solid 1px',
                    background: 'transparent',
                    padding: '0 4px',
                    margin: '0 2px',
                    height: 'auto',
                    fontSize: '16px', // Adjust to match surrounding text
                    textAlign: 'center',
                    color: 'inherit',
                  }}
                  // className="appearance-none border border-black bg-transparent px-1 py-0 mx-0 mr-1 h-auto text-base text-center text-current  align-middle cursor-pointer"

                  //className="form-select mx-2 h-8 text-gray-600"
                  value={repeatFrequency || 1}
                  onChange={(e) => setRepeatFrequency(e.target.value)}
                >
                  <option value="1">1</option>
                  <option value="2">2</option>
                  <option value="3">3</option>
                  <option value="4">4</option>
                </select>
              )} */}
              седмица
              <span className="checkmark"></span>
            </label>
          </div>

          {false && repeatWeekly && (

            <div className="mb-2">
              <DatePicker label="До" value={repeatUntil} onChange={(value) => setRepeatUntil({ value })} />
            </div>
          )}
          <div>
            <div className="mb-1">
              {/* Time slot checkboxes */}
              <TimeSlotCheckboxes slots={timeSlots} setSlots={setTimeSlots} items={availabilities} />
            </div>
          </div>

        </LocalizationProvider>

        <div className="flex justify-between items-center flex-nowrap w-full p-1">
          <button className="button border border-blue-500 text-blue-500 bg-transparent hover:text-white focus:outline-none focus:shadow-outline" onClick={() => handleCompletion()}> Отмени </button>

          {editMode && (
            <><button className="button btn-outline bg-red-500 hover:bg-red-700 focus:outline-none focus:shadow-outline" type="button" onClick={handleDelete}>
              Изтрий
            </button></>
          )}
          <button
            className={`button bg-blue-500 hover:bg-blue-700 focus:outline-none focus:shadow-outline ${!canUpdate ? 'opacity-50 cursor-not-allowed' : ''}`}
            disabled={!canUpdate}
          > {editMode ? "Обнови" : "Запиши"}
          </button>
        </div>
      </form>
    </div>

  );
}
