/** @jsxRuntime classic */
/** @jsx jsx */

import { FC, useEffect, useMemo, useState } from 'react';
import { useTheme, jsx } from '@emotion/react';
import dayjs from 'dayjs';
import isoWeek from 'dayjs/plugin/isoWeek';
import { Droppable } from '../Droppable';
import { IWeekToDropProps, ISlot } from '../../types';
import { useMiddlewareContext } from '../../hooks/useMiddlewareContext';
import {
  monthlyDateContainer,
  monthlyViewContainer,
  moreItemsButton,
  moreModal,
  spaceWidth,
  weekDayContainer,
  weekDayEventContainer,
} from '../styles';
import { BnClose } from '../../../icons/BnClose';
import { WeeklyDraggable } from '../weekly/WeeklyDraggable';
import { calculateModalPosition } from '../../utils';

dayjs.extend(isoWeek);

export const MonthlyView: FC<IWeekToDropProps> = ({ id, EventComponent }) => {
  const colors = useTheme();
  const { options, eventsToSpaces } = useMiddlewareContext();
  const { date: optionsDate, isSundayFirstDay } = options;
  const dayShift = isSundayFirstDay ? 1 : 0;
  const today = dayjs.utc(optionsDate);
  const currentMonth = today.month();

  const { dates, withSixth } = useMemo(() => {
    let result = [] as dayjs.Dayjs[];
    let withSixth = true;

    for (let i = 1; i < 7 * 6 + 1; i++) {
      const date = today.set('date', 1).isoWeekday(i - dayShift);

      // dont render other days if 1st day of 6th week is next month
      if (i === 36 && currentMonth !== date.month()) {
        withSixth = false;
        break;
      }

      result.push(date);
    }

    return { dates: result, withSixth };
  }, [dayShift, optionsDate]);

  const weekDaysWithEvents = useMemo(() => {
    let result = [] as { date: dayjs.Dayjs; events: ISlot[] }[];

    dates.forEach((date) =>
      result.push({
        date,
        events:
          eventsToSpaces[Number(id)]
            ?.filter((event: ISlot) =>
              date.isSame(dayjs.utc(event.startDate), 'date')
            )
            .sort(
              (a: ISlot, b: ISlot) =>
                dayjs.utc(a.startDate).toDate().getTime() -
                dayjs.utc(b.startDate).toDate().getTime()
            ) || [],
      })
    );

    return result;
  }, [dates, eventsToSpaces, id]);

  const [modals, setModals] = useState<boolean[]>([]);

  useEffect(() => {
    setModals(Array(dates.length).fill(false));
  }, [dates.length]);

  const handleToggleModal = (index: number) => {
    let newModals = modals.slice();
    newModals[index] = !newModals[index];
    setModals(newModals);
  };

  let maxVisibleSlotsPerDay = 1;
  const todayContainer = document.getElementById('today-container');
  if (todayContainer) {
    const height = todayContainer.clientHeight - 20;
    maxVisibleSlotsPerDay = Math.floor(height / 18) + 1;
  }

  return (
    <div css={monthlyViewContainer}>
      {weekDaysWithEvents.map((weekDay, index) => {
        const droppableId = `${id}_${weekDay.date.toISOString()}`;

        const withModal = weekDay.events.length > maxVisibleSlotsPerDay;
        const items = withModal
          ? weekDay.events.slice(0, maxVisibleSlotsPerDay - 1)
          : weekDay.events;

        const isCurrentMonth = today.isSame(weekDay.date, 'month');
        const isToday =
          today.isSame(weekDay.date, 'month') &&
          today.isSame(weekDay.date, 'date') &&
          today.isSame(weekDay.date, 'year');
        const isSeventh = (index + 1) % 7 === 0;

        const element = document.querySelector(
          `#draggable-${weekDay.events[0]?.id}`
        );
        const box = element?.parentElement?.parentElement;
        const container = box?.parentElement?.parentElement;
        const containerW = container?.parentElement?.parentElement;

        return (
          <Droppable
            weekly
            dragging={false}
            id={droppableId}
            key={droppableId + index}
            height={`calc(100% / ${withSixth ? 6 : 5})`}
            maxWidth={`max(100% / 7, ${spaceWidth}px )`}
          >
            <div
              css={monthlyDateContainer(
                colors,
                isCurrentMonth,
                isToday,
                isSeventh
              )}
            >
              <div className="date">{weekDay.date.format('DD')}</div>
              <div
                id={isToday ? 'today-container' : undefined}
                css={weekDayContainer(colors, undefined, 'calc(100% - 16px)')}
              >
                {items.map((event) => (
                  <WeeklyDraggable
                    parentId={droppableId}
                    state={event}
                    key={event.id}
                    id={event.id}
                  >
                    <div css={weekDayEventContainer} key={event.id}>
                      <EventComponent event={event} />
                    </div>
                  </WeeklyDraggable>
                ))}
                {withModal && (
                  <button
                    css={moreItemsButton(colors, true)}
                    onClick={() => handleToggleModal(index)}
                  >
                    <div>
                      +{weekDay.events.length - (maxVisibleSlotsPerDay - 1)}
                    </div>
                    <div>{'more'}</div>
                  </button>
                )}
                {withModal && modals[index] && (
                  <div
                    css={moreModal(
                      colors,
                      calculateModalPosition(box, container, box, containerW)
                    )}
                  >
                    <div className="more-modal-header">
                      <div onClick={() => handleToggleModal(index)}>
                        <BnClose />
                      </div>
                    </div>
                    <div className="events-list">
                      {weekDay.events.map((event) => (
                        <div key={event.id} css={{ margin: 2, height: '50px' }}>
                          <EventComponent event={event} />
                        </div>
                      ))}
                    </div>
                  </div>
                )}
              </div>
            </div>
          </Droppable>
        );
      })}
    </div>
  );
};
