'use client';

import React, {
  FC,
  Fragment,
  useCallback,
  useEffect,
  useMemo,
  useState,
} from 'react';
import {
  Integrations,
  useCalendar,
} from '@gitroom/frontend/components/launches/calendar.context';
import dayjs from 'dayjs';
import { openModal, useModals } from '@mantine/modals';
import { AddEditModal } from '@gitroom/frontend/components/launches/add.edit.model';
import clsx from 'clsx';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { ExistingDataContextProvider } from '@gitroom/frontend/components/launches/helpers/use.existing.data';
import { useDrag, useDrop } from 'react-dnd';
import { DNDProvider } from '@gitroom/frontend/components/launches/helpers/dnd.provider';
import { Integration, Post, State } from '@prisma/client';
import { useAddProvider } from '@gitroom/frontend/components/launches/add.provider.component';
import { CommentComponent } from '@gitroom/frontend/components/launches/comments/comment.component';
import { useSWRConfig } from 'swr';
import { useToaster } from '@gitroom/react/toaster/toaster';
import { useUser } from '@gitroom/frontend/components/layout/user.context';
import { IntegrationContext } from '@gitroom/frontend/components/launches/helpers/use.integration';
import { PreviewPopup } from '@gitroom/frontend/components/marketplace/special.message';
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
dayjs.extend(isSameOrAfter);
dayjs.extend(isSameOrBefore);

export const days = [
  'Monday',
  'Tuesday',
  'Wednesday',
  'Thursday',
  'Friday',
  'Saturday',
  'Sunday',
];
export const hours = Array.from({ length: 24 }, (_, i) => i);

export const WeekView = () => {
  const { currentYear, currentWeek } = useCalendar();

  return (
    <div className="flex flex-col h-screen overflow-hidden text-textColor flex-1">
      <div className="flex-1">
        <div className="grid grid-cols-8 bg-customColor31 gap-[1px] border-customColor31 border rounded-[10px]">
          <div className="bg-customColor20 sticky top-0 z-10 bg-gray-900"></div>
          {days.map((day, index) => (
            <div
              key={day}
              className="sticky top-0 z-10 bg-customColor20 p-2 text-center"
            >
              <div>{day}</div>
            </div>
          ))}
          {hours.map((hour) => (
            <Fragment key={hour}>
              <div className="p-2 pr-4 bg-secondary text-center items-center justify-center flex">
                {hour.toString().padStart(2, '0')}:00
              </div>
              {days.map((day, indexDay) => (
                <Fragment key={`${day}-${hour}`}>
                  <div className="relative bg-secondary">
                    <CalendarColumn
                      getDate={dayjs()
                        .year(currentYear)
                        .week(currentWeek)
                        .day(indexDay + 1)
                        .hour(hour)
                        .startOf('hour')}
                    />
                  </div>
                </Fragment>
              ))}
            </Fragment>
          ))}
        </div>
      </div>
    </div>
  );
};

export const MonthView = () => {
  const { currentYear, currentMonth } = useCalendar();

  const calendarDays = useMemo(() => {
    const startOfMonth = dayjs(new Date(currentYear, currentMonth, 1));

    // Calculate the day offset for Monday (isoWeekday() returns 1 for Monday)
    const startDayOfWeek = startOfMonth.isoWeekday(); // 1 for Monday, 7 for Sunday
    const daysBeforeMonth = startDayOfWeek - 1; // Days to show from the previous month

    // Get the start date (Monday of the first week that includes this month)
    const startDate = startOfMonth.subtract(daysBeforeMonth, 'day');

    // Create an array to hold the calendar days (6 weeks * 7 days = 42 days max)
    const calendarDays = [];
    let currentDay = startDate;

    for (let i = 0; i < 42; i++) {
      let label = 'current-month';
      if (currentDay.month() < currentMonth) label = 'previous-month';
      if (currentDay.month() > currentMonth) label = 'next-month';

      calendarDays.push({
        day: currentDay,
        label,
      });

      // Move to the next day
      currentDay = currentDay.add(1, 'day');
    }

    return calendarDays;
  }, [currentYear, currentMonth]);

  return (
    <div className="flex flex-col h-screen overflow-hidden text-textColor flex-1">
      <div className="flex-1 flex">
        <div className="grid grid-cols-7 grid-rows-[40px_auto] bg-customColor31 gap-[1px] border-customColor31 border rounded-[10px] flex-1">
          {days.map((day) => (
            <div
              key={day}
              className="sticky top-0 z-10 bg-customColor20 p-2 text-center"
            >
              <div>{day}</div>
            </div>
          ))}
          {calendarDays.map((date, index) => (
            <div
              key={index}
              className="bg-secondary text-center items-center justify-center flex min-h-[100px]"
            >
              <CalendarColumn
                getDate={dayjs(date.day).endOf('day')}
                randomHour={true}
              />
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

export const Calendar = () => {
  const { display } = useCalendar();

  return (
    <DNDProvider>
      {display === 'week' ? <WeekView /> : <MonthView />}
    </DNDProvider>
  );
};

export const CalendarColumn: FC<{
  getDate: dayjs.Dayjs;
  randomHour?: boolean;
}> = (props) => {
  const { getDate, randomHour } = props;
  const user = useUser();
  const {
    integrations,
    posts,
    trendings,
    changeDate,
    display,
    reloadCalendarView,
  } = useCalendar();

  const toaster = useToaster();
  const modal = useModals();
  const fetch = useFetch();

  const postList = useMemo(() => {
    return posts.filter((post) => {
      const pList = dayjs.utc(post.publishDate).local();
      const check =
        display === 'week'
          ? pList.isSameOrAfter(getDate.startOf('hour')) &&
            pList.isBefore(getDate.endOf('hour'))
          : pList.format('DD/MM/YYYY') === getDate.format('DD/MM/YYYY');

      return check;
    });
  }, [posts, display, getDate]);

  const canBeTrending = useMemo(() => {
    return !!trendings.find((trend) => {
      return dayjs
        .utc(trend)
        .local()
        .isBetween(getDate, getDate.add(10, 'minute'), 'minute', '[)');
    });
  }, [trendings]);

  const isBeforeNow = useMemo(() => {
    return getDate.startOf('hour').isBefore(dayjs().startOf('hour'));
  }, [getDate]);

  const [{ canDrop }, drop] = useDrop(() => ({
    accept: 'post',
    drop: async (item: any) => {
      if (isBeforeNow) return;
      const { status } = await fetch(`/posts/${item.id}/date`, {
        method: 'PUT',
        body: JSON.stringify({
          date: getDate.utc().format('YYYY-MM-DDTHH:mm:ss'),
        }),
      });

      if (status !== 500) {
        changeDate(item.id, getDate);
        return;
      }

      toaster.show(
        "Can't change date, remove post from publication",
        'warning'
      );
    },
    collect: (monitor) => ({
      canDrop: isBeforeNow ? false : !!monitor.canDrop() && !!monitor.isOver(),
    }),
  }));

  const getIntegration = useCallback(
    async (post: Post & { integration: Integration }) => {
      return (
        await fetch(
          `/integrations/${post.integration.id}?order=${post.submittedForOrderId}`,
          {
            method: 'GET',
          }
        )
      ).json();
    },
    []
  );

  const previewPublication = useCallback(
    async (postInfo: Post & { integration: Integration }) => {
      const post = await (
        await fetch(`/marketplace/posts/${postInfo.id}`)
      ).json();

      const integration = await getIntegration(postInfo);
      modal.openModal({
        classNames: {
          modal: 'bg-transparent text-textColor',
        },
        size: 'auto',
        withCloseButton: false,
        children: (
          <IntegrationContext.Provider
            value={{
              date: dayjs(),
              integration,
              value: [],
            }}
          >
            <PreviewPopup
              providerId={post?.providerId!}
              post={post}
              postId={post.id}
            />
          </IntegrationContext.Provider>
        ),
      });
    },
    []
  );

  const editPost = useCallback(
    (post: Post & { integration: Integration }) => async () => {
      if (user?.orgId === post.submittedForOrganizationId) {
        return previewPublication(post);
      }
      const data = await (await fetch(`/posts/${post.id}`)).json();
      const publishDate = dayjs.utc(data.posts[0].publishDate).local();

      modal.openModal({
        closeOnClickOutside: false,
        closeOnEscape: false,
        withCloseButton: false,
        classNames: {
          modal: 'w-[100%] max-w-[1400px] bg-transparent text-textColor',
        },
        children: (
          <ExistingDataContextProvider value={data}>
            <AddEditModal
              reopenModal={editPost(post)}
              mutate={reloadCalendarView}
              integrations={integrations
                .slice(0)
                .filter((f) => f.id === data.integration)
                .map((p) => ({ ...p, picture: data.integrationPicture }))}
              date={publishDate}
            />
          </ExistingDataContextProvider>
        ),
        size: '80%',
        title: ``,
      });
    },
    [integrations]
  );

  const addModal = useCallback(() => {
    modal.openModal({
      closeOnClickOutside: false,
      closeOnEscape: false,
      withCloseButton: false,
      classNames: {
        modal: 'w-[100%] max-w-[1400px] bg-transparent text-textColor',
      },
      children: (
        <AddEditModal
          integrations={integrations.slice(0).map((p) => ({ ...p }))}
          mutate={reloadCalendarView}
          date={
            randomHour ? getDate.hour(Math.floor(Math.random() * 24)) : getDate
          }
          reopenModal={() => ({})}
        />
      ),
      size: '80%',
      // title: `Adding posts for ${getDate.format('DD/MM/YYYY HH:mm')}`,
    });
  }, [integrations, getDate]);

  const addProvider = useAddProvider();

  return (
    <div className="flex flex-col w-full min-h-full" ref={drop}>
      {display === 'month' && (
        <div className={clsx('pt-[5px]', isBeforeNow && 'bg-customColor23')}>
          {getDate.date()}
        </div>
      )}
      <div
        className={clsx(
          'relative flex flex-col flex-1',
          canDrop && 'bg-white/80'
        )}
      >
        <div
          {...(canBeTrending
            ? {
                'data-tooltip-id': 'tooltip',
                'data-tooltip-content': 'Predicted GitHub Trending Change',
              }
            : {})}
          className={clsx(
            'flex-col text-[12px] pointer w-full cursor-pointer overflow-hidden overflow-x-auto flex scrollbar scrollbar-thumb-tableBorder scrollbar-track-secondary',
            isBeforeNow && 'bg-customColor23 flex-1',
            canBeTrending && 'bg-customColor24'
          )}
        >
          {postList.map((post) => (
            <div
              key={post.id}
              className={clsx(
                'text-textColor p-[2.5px] relative flex flex-col justify-center items-center'
              )}
            >
              <div className="relative w-full flex flex-col items-center p-[2.5px]">
                <CalendarItem
                  isBeforeNow={isBeforeNow}
                  date={getDate}
                  state={post.state}
                  editPost={editPost(post)}
                  post={post}
                  integrations={integrations}
                />
              </div>
            </div>
          ))}
        </div>
        {!isBeforeNow && (
          <div
            className="pb-[2.5px] px-[5px] flex-1 flex"
            onClick={integrations.length ? addModal : addProvider}
          >
            <div
              className={clsx(
                display === 'month'
                  ? 'flex-1 min-h-[40px] w-full'
                  : !postList.length
                  ? 'h-full w-full absolute left-0 top-0 p-[5px]'
                  : 'min-h-[40px] w-full',
                'flex items-center justify-center cursor-pointer pb-[2.5px]'
              )}
            >
              <div
                className={clsx(
                  'hover:before:content-["+"] w-full h-full text-seventh rounded-[10px] hover:border hover:border-seventh flex justify-center items-center'
                )}
              />
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

const CalendarItem: FC<{
  date: dayjs.Dayjs;
  isBeforeNow: boolean;
  editPost: () => void;
  integrations: Integrations[];
  state: State;
  post: Post & { integration: Integration };
}> = (props) => {
  const { editPost, post, date, isBeforeNow, state } = props;
  const [{ opacity }, dragRef] = useDrag(
    () => ({
      type: 'post',
      item: { id: post.id, date },
      collect: (monitor) => ({
        opacity: monitor.isDragging() ? 0 : 1,
      }),
    }),
    []
  );
  return (
    <div
      ref={dragRef}
      onClick={editPost}
      className={clsx(
        'gap-[5px] w-full flex h-full flex-1 rounded-[10px] border border-seventh px-[5px] p-[2.5px]',
        'relative',
        (state === 'DRAFT' || isBeforeNow) && '!grayscale'
      )}
      style={{ opacity }}
    >
      <div className="relative min-w-[20px] h-[20px]">
        <img
          className="w-[20px] h-[20px] rounded-full"
          src={post.integration.picture!}
        />
        <img
          className="w-[12px] h-[12px] rounded-full absolute z-10 bottom-[0] right-0 border border-fifth"
          src={`/icons/platforms/${post.integration?.providerIdentifier}.png`}
        />
      </div>
      <div className="whitespace-pre-wrap line-clamp-3">
        {state === 'DRAFT' ? 'Draft: ' : ''}
        {post.content}
      </div>
    </div>
  );
};

export const CommentBox: FC<{ totalComments: number; date: dayjs.Dayjs }> = (
  props
) => {
  const { totalComments, date } = props;
  const { mutate } = useSWRConfig();

  const openCommentsModal = useCallback(() => {
    openModal({
      children: <CommentComponent date={date} />,
      withCloseButton: false,
      onClose() {
        mutate(`/posts`);
      },
      classNames: {
        modal: 'bg-transparent text-textColor',
      },
      size: '80%',
    });
  }, [date]);

  return (
    <div
      className={
        totalComments === 0
          ? 'transition-opacity opacity-0 group-hover:opacity-100'
          : ''
      }
    >
      <div
        onClick={openCommentsModal}
        data-tooltip-id="tooltip"
        data-tooltip-content="Add / View comments"
        className={clsx(
          'group absolute right-0 bottom-0 w-[20px] h-[20px] z-[10] hover:opacity-95 cursor-pointer hover:right-[3px] hover:bottom-[3px] transition-all duration-300 ease-in-out',
          totalComments === 0 ? 'opacity-50' : 'opacity-95'
        )}
      >
        <div
          className={clsx(
            'relative w-full h-full group-hover:opacity-100',
            totalComments === 0 && 'opacity-0'
          )}
        >
          {totalComments > 0 && (
            <div className="absolute right-0 bottom-[10px] w-[10px] h-[10px] text-[8px] bg-red-500 z-[20] rounded-full flex justify-center items-center text-textColor">
              {totalComments}
            </div>
          )}
          <svg
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 32 32"
            id="comment"
          >
            <path
              fill="#fff"
              d="M25.784 21.017A10.992 10.992 0 0 0 27 16c0-6.065-4.935-11-11-11S5 9.935 5 16s4.935 11 11 11c1.742 0 3.468-.419 5.018-1.215l4.74 1.185a.996.996 0 0 0 .949-.263 1 1 0 0 0 .263-.95l-1.186-4.74zm-2.033.11.874 3.498-3.498-.875a1.006 1.006 0 0 0-.731.098A8.99 8.99 0 0 1 16 25c-4.963 0-9-4.038-9-9s4.037-9 9-9 9 4.038 9 9a8.997 8.997 0 0 1-1.151 4.395.995.995 0 0 0-.098.732z"
            ></path>
          </svg>
        </div>
        <div className="absolute right-0 bottom-0 w-[0] h-[0] shadow-yellow bg-[rgba(0,0,0,0)]"></div>
      </div>
    </div>
  );
};
