import React, { useState, useLayoutEffect, useRef } from "react";
import { DayPickerSingleDateController } from "react-dates";
import DatePickerFooter from "./datePickerFooter";
import ShowMonthYearSelect from "./showMonthYearSelect";
import moment from "moment";
import Portal from "../Portal";

export default function DatePickerDropdown({
  datePickerMainContainer,
  onDatesChange,
  focused,
  setFocused,
  selectedDate,
  setSelectedDate,
  showWeekNumbers,
  setIsOpen,
  withPortal,
  portalContainer,
  containerRef,
  showMonthYearSelect,
  customYears,
  tertiaryButtonProps,
  primaryButtonProps,
  onTertiaryButtonClick,
  onSecondaryButtonClick,
  onPrimaryButtonClick,
  minDate,
  maxDate,
  placement,
  hideTertiaryButton,
  hideSecondaryButton,
  hidePrimaryButton,
  dropdownRef: externalDropdownRef,
  allButtonsHidden,
  ...args
}) {
  const [position, setPosition] = useState({
    x: 0,
    y: 0,
    offsetHeight: 0,
    offsetWidth: 0,
  });

  const internalDropdownRef = useRef(null);
  const dropdownRef = externalDropdownRef || internalDropdownRef;
  const [dropdownWidth, setDropdownWidth] = useState(269);
  const [dropdownHeight, setDropdownHeight] = useState(
    allButtonsHidden ? 250 : 300
  );

  useLayoutEffect(() => {
    let frame = null;

    const update = () => {
      if (!containerRef?.current) return;

      const scrollY = window.scrollY || document.documentElement.scrollTop;
      const {
        x,
        y,
        height: offsetHeight,
        width: offsetWidth,
      } = containerRef.current.getBoundingClientRect();
      setPosition({ x, y: y + scrollY, offsetHeight, offsetWidth });

      if (dropdownRef.current) {
        const rect = dropdownRef.current.getBoundingClientRect();
        if (rect.width) setDropdownWidth(rect.width);
        if (rect.height) setDropdownHeight(rect.height);
      }
    };

    const scheduleUpdate = () => {
      if (frame !== null) return;
      frame = requestAnimationFrame(() => {
        update();
        frame = null;
      });
    };

    // Initial measure
    update();

    // Schedule a second measure after paint so the dropdown DOM is fully rendered
    let rafOuter = requestAnimationFrame(() => {
      rafOuter = null;
      rafOuter = requestAnimationFrame(() => {
        rafOuter = null;
        update();
      });
    });

    window.addEventListener("resize", scheduleUpdate);
    window.addEventListener("scroll", scheduleUpdate, true);

    return () => {
      window.removeEventListener("resize", scheduleUpdate);
      window.removeEventListener("scroll", scheduleUpdate, true);
      if (frame !== null) cancelAnimationFrame(frame);
      if (rafOuter !== null) cancelAnimationFrame(rafOuter);
    };
  }, [
    containerRef,
    placement,
    withPortal,
    showMonthYearSelect,
    showWeekNumbers,
    allButtonsHidden,
  ]);

  const onPrevMonthClick = (params) => {
    const isNavButtonFocused =
      document.activeElement?.classList.contains(
        "DayPickerNavigation_leftButton__horizontalDefault"
      );
  
    if (isNavButtonFocused) {
      setTimeout(() => {
        const btn = dropdownRef.current?.querySelector(
          ".DayPickerNavigation_leftButton__horizontalDefault"
        );
  
        btn?.focus();
      }, 0);
    }
  
    args.onPrevMonthClick?.(params);
  };
  
  const onNextMonthClick = (params) => {
    const isNavButtonFocused =
      document.activeElement?.classList.contains(
        "DayPickerNavigation_rightButton__horizontalDefault"
      );
  
    if (isNavButtonFocused) {
      setTimeout(() => {
        const btn = dropdownRef.current?.querySelector(
          ".DayPickerNavigation_rightButton__horizontalDefault"
        );
  
        btn?.focus();
      }, 0);
    }
  
    args.onNextMonthClick?.(params);
  };

  const handleDateChange = (date) => {
    if (date) {
      const newDate = moment(date);
      onDatesChange(newDate);
    } else {
      onDatesChange(null);
    }
  };

  const renderDayContents = React.useCallback((momentInstance, modifiers) => {
    // Calculate the week number within the month
    const startOfMonth = momentInstance.clone().startOf("month");
    const weekNumber = Math.ceil(
      (momentInstance.date() - 1 + startOfMonth.day()) / 7
    );

    return (
      <>
        {/* Add week numbers, adds one button each row */}
        {showWeekNumbers && modifiers.has("first-day-of-week") && (
          <span className="CalendarDayWeekNumber">W{weekNumber + 1}</span>
        )}
        <span className="CalendarDayNumber">{momentInstance.format("D")}</span>
      </>
    );
  }, []);

  const renderCalendar = () => {
    const currentDate = selectedDate ? moment(selectedDate) : null;
    return (
      <DayPickerSingleDateController
        key={`calendar-${withPortal ? "portal" : "inline"}-${
          focused ? "focused" : "unfocused"
        }`}
        onDateChange={handleDateChange}
        onFocusChange={() => setFocused(true)}
        focused={focused}
        date={currentDate}
        initialMonth={currentDate || moment()}
        hideKeyboardShortcutsPanel={true}
        daySize={26}
        horizontalMonthPadding={showWeekNumbers ? 24 : 12}
        renderDayContents={showWeekNumbers ? renderDayContents : undefined}
        renderMonthElement={
          showMonthYearSelect
            ? ({ month, onMonthSelect, onYearSelect }) => (
                <ShowMonthYearSelect
                  customYears={customYears}
                  month={month}
                  onMonthSelect={onMonthSelect}
                  onYearSelect={onYearSelect}
                  minDate={minDate}
                  maxDate={maxDate}
                />
              )
            : undefined
        }
        onPrevMonthClick={onPrevMonthClick}
        onNextMonthClick={onNextMonthClick}
        {...args}
      />
    );
  };

  if (withPortal) {
    const spacing = 6;
    const scrollX = window.scrollX || document.documentElement.scrollLeft;
    const scrollY = window.scrollY || document.documentElement.scrollTop;
    const viewportWidth = window.innerWidth;
    const viewportTopOffset = 64;
    const top =
      placement === "top"
        ? position.y - dropdownHeight - spacing
        : position.y + position.offsetHeight + spacing;

    const clampedTop = Math.max(viewportTopOffset + scrollY, top);

    const rightPadding = 10;
    const leftPadding = 10;
    const triggerRight = position.x + position.offsetWidth;
    const wouldOverflowRight =
      position.x + dropdownWidth > viewportWidth - rightPadding;

    const viewportLeft = wouldOverflowRight
      ? triggerRight - dropdownWidth
      : position.x;

    const clampedViewportLeft = Math.min(
      Math.max(leftPadding, viewportLeft),
      viewportWidth - dropdownWidth - rightPadding
    );
    const documentLeft = clampedViewportLeft + scrollX;

    return (
      <Portal container={portalContainer}>
        <div
          className="impact-portal-container"
          style={{
            top: clampedTop,
            left: documentLeft,
            width: (position.offsetWidth || 0) + "px",
          }}
        >
          <div
            className={`impact-date-picker-dropdown-container impact-date-picker-dropdown-portal ${
              showWeekNumbers ? "showWeekNumbers" : ""
            }`}
            ref={dropdownRef}
          >
            {renderCalendar()}
            <DatePickerFooter
              tertiaryButtonProps={tertiaryButtonProps}
              primaryButtonProps={primaryButtonProps}
              setSelectedDate={setSelectedDate}
              setFocused={setFocused}
              onSecondaryButtonClick={onSecondaryButtonClick}
              onPrimaryButtonClick={onPrimaryButtonClick}
              onTertiaryButtonClick={onTertiaryButtonClick}
              setIsOpen={setIsOpen}
              hideTertiaryButton={hideTertiaryButton}
              hideSecondaryButton={hideSecondaryButton}
              hidePrimaryButton={hidePrimaryButton}
            />
          </div>
        </div>
        <div
          className="ia-select-container-v3-blanket"
          onClick={() => setIsOpen(false)}
        />
      </Portal>
    );
  }

  const viewportWidth = window.innerWidth;
  const rightPadding = 10;
  const leftPadding = 10;

  const triggerRight = position.x + position.offsetWidth;
  const wouldOverflowRight =
    position.x + dropdownWidth > viewportWidth - rightPadding;
  const viewportLeft = wouldOverflowRight
    ? triggerRight - dropdownWidth
    : position.x;
  const clampedViewportLeft = Math.min(
    Math.max(leftPadding, viewportLeft),
    viewportWidth - dropdownWidth - rightPadding
  );
  const relativeLeft = clampedViewportLeft - position.x;

  return (
    <div
      className={`impact-date-picker-dropdown-container ${
        placement === "top" ? "impact-date-picker-dropdown-top" : ""
      } ${showWeekNumbers ? "showWeekNumbers" : ""}`}
      style={{ left: relativeLeft }}
      ref={dropdownRef}
    >
      {renderCalendar()}
      <DatePickerFooter
        tertiaryButtonProps={tertiaryButtonProps}
        primaryButtonProps={primaryButtonProps}
        setSelectedDate={setSelectedDate}
        setFocused={setFocused}
        onTertiaryButtonClick={onTertiaryButtonClick}
        onSecondaryButtonClick={onSecondaryButtonClick}
        onPrimaryButtonClick={onPrimaryButtonClick}
        setIsOpen={setIsOpen}
        hideTertiaryButton={hideTertiaryButton}
        hideSecondaryButton={hideSecondaryButton}
        hidePrimaryButton={hidePrimaryButton}
      />
    </div>
  );
}
