import { shallow } from "zustand/shallow";

import dayjs from "@calcom/dayjs";
import { useBookerStoreContext } from "@calcom/features/bookings/Booker/BookerStoreProvider";
import type { BookerState } from "@calcom/features/bookings/Booker/types";
import { getPrefetchMonthCount } from "@calcom/features/bookings/Booker/utils/getPrefetchMonthCount";
import { isPrefetchNextMonthEnabled } from "@calcom/features/bookings/Booker/utils/isPrefetchNextMonthEnabled";

type UseScheduleWithCacheArgs = {
  username?: string | null;
  eventSlug?: string | null;
  eventId?: number | null;
  month?: string | null;
  timezone?: string | null;
  selectedDate?: string | null;
  duration?: number | null;
  dayCount?: number | null;
  rescheduleUid?: string | null;
  isTeamEvent?: boolean;
  orgSlug?: string;
  teamMemberEmail?: string | null;
  useApiV2?: boolean;
  enabled?: boolean;
  /***
   * Required when prefetching is needed
   */
  bookerLayout?: {
    layout: string;
    extraDays: number;
    columnViewExtraDays: { current: number };
  };
};

type UseTimesForScheduleProps = Pick<
  UseScheduleWithCacheArgs,
  "month" | "dayCount" | "selectedDate" | "bookerLayout"
>;

interface UsePrefetchParams {
  date: string;
  month: string | null;
  bookerLayout?: {
    layout: string;
    extraDays: number;
    columnViewExtraDays: { current: number };
  };
  bookerState: BookerState;
}

const usePrefetch = ({ date, month, bookerLayout, bookerState }: UsePrefetchParams) => {
  if (!bookerLayout) {
    return null;
  }

  const dateMonth = dayjs(date).month();
  const monthAfterAdding1Month = dayjs(date).add(1, "month").month();
  const monthAfterAddingExtraDays = dayjs(date).add(bookerLayout.extraDays, "day").month();
  const monthAfterAddingExtraDaysColumnView = dayjs(date)
    .add(bookerLayout.columnViewExtraDays.current, "day")
    .month();

  const prefetchNextMonth = isPrefetchNextMonthEnabled(
    bookerLayout.layout,
    date,
    dateMonth,
    monthAfterAddingExtraDays,
    monthAfterAddingExtraDaysColumnView,
    month,
    bookerLayout.extraDays
  );

  if (!prefetchNextMonth) {
    return null;
  }

  const monthCount = getPrefetchMonthCount(
    bookerLayout.layout,
    bookerState,
    monthAfterAdding1Month,
    monthAfterAddingExtraDaysColumnView,
    prefetchNextMonth
  );

  return { monthsToPrefetch: monthCount ?? 1 };
};

export const useTimesForSchedule = ({
  month: monthFromProps,
  selectedDate,
  dayCount,
  bookerLayout,
}: UseTimesForScheduleProps): [string, string] => {
  const [monthFromStore, bookerState] = useBookerStoreContext((state) => [state.month, state.state], shallow);
  const month = monthFromStore ?? monthFromProps ?? null;
  const date = dayjs(selectedDate).format("YYYY-MM-DD");
  const prefetchData = usePrefetch({
    date,
    month,
    bookerLayout,
    bookerState,
  });

  const now = dayjs();
  const monthDayjs = month ? dayjs(month) : now;

  let startTime;
  let endTime;

  if (!!dayCount && dayCount > 0) {
    if (selectedDate) {
      startTime = dayjs(selectedDate).toISOString();
      endTime = dayjs(selectedDate).add(dayCount, "day").toISOString();
    } else if (monthDayjs.month() === now.month()) {
      startTime = now.startOf("day").toISOString();
      endTime = now.startOf("day").add(dayCount, "day").toISOString();
    } else {
      startTime = monthDayjs.startOf("month").toISOString();
      endTime = monthDayjs.startOf("month").add(dayCount, "day").toISOString();
    }
  } else {
    const monthsToPrefetch = prefetchData?.monthsToPrefetch;
    const lastMonthToPrefetchDayjs = monthsToPrefetch ? monthDayjs.add(monthsToPrefetch, "month") : null;
    startTime = monthDayjs.startOf("month").toISOString();
    endTime = (lastMonthToPrefetchDayjs ? lastMonthToPrefetchDayjs : monthDayjs).endOf("month").toISOString();
  }
  return [startTime, endTime];
};
