import "react-dates/initialize";
import "react-dates/lib/css/_datepicker.css";
import React, { forwardRef, useEffect, useMemo, useRef, useState } from "react";
import DatePickerInput from "./datePickerInput";
import DatePickerDropdown from "./datePickerDropdown";
import "./DatePicker.styles.scss";
import moment from "moment";

export const DatePicker = forwardRef(
  (
    {
      fullWidth,
      label,
      isRequired,
      labelOrientation,
      showRangeSelector,
      isError,
      isDisabled,
      showInputs,
      closeOnDateSelect,
      placeholder,
      initialDate,
      inputProps,
      selectedDate,
      setSelectedDate,
      handleDateChange,
      //showOnlyCalender,
      showWeekNumbers,
      primaryButtonProps,
      secondaryButtonProps,
      tertiaryButtonProps,
      onPrimaryButtonClick,
      onSecondaryButtonClick,
      onTertiaryButtonClick,
      withPortal,
      portalContainer = document.body,
      showMonthYearSelect,
      customYears,
      displayFormat = "DD-MM-YYYY",
      minDate,
      maxDate,
      onClickOutside,
      isOutsideRange,
      isAgGridCellRenderer = false,
      customIcon,
      hideTertiaryButton = false,
      hideSecondaryButton = false,
      hidePrimaryButton = false,
      ...args
    },
    ref
  ) => {
    const dateString =
      selectedDate && moment.isMoment(selectedDate) && selectedDate.isValid()
        ? selectedDate.format(displayFormat)
        : "";
    const datePickerMainContainerRef = useRef(null);
    const inputContainerRef = useRef(null);
    const dropdownRef = useRef(null);
    const [isOpen, setIsOpen] = useState(false);
    const [focused, setFocused] = useState(false);
    const [inputValue, setInputValue] = useState(dateString || "");
    const [cancelTrigger, setCancelTrigger] = useState(0);
    const [placement, setPlacement] = useState("bottom");
    const allButtonsHidden =
      hideTertiaryButton && hideSecondaryButton && hidePrimaryButton;

    useEffect(() => {
      setInputValue(dateString || "");
    }, [dateString]);

    const updatePlacement = () => {
      const rect = datePickerMainContainerRef.current?.getBoundingClientRect();
      if (!rect) return;

      const viewportHeight = window.innerHeight;
      const spacing = 6;
      const measuredHeight =
        dropdownRef.current?.getBoundingClientRect().height;
      const dropdownHeight = measuredHeight || (allButtonsHidden ? 250 : 300);

      const spaceBelow = viewportHeight - rect.bottom;

      if (spaceBelow >= dropdownHeight + spacing) {
        setPlacement("bottom");
      } else {
        setPlacement("top");
      }
    };

    useEffect(() => {
      if (!isOpen) return;

      let frame = null;
      const handleUpdate = () => {
        if (frame !== null) return;
        frame = requestAnimationFrame(() => {
          updatePlacement();
          frame = null;
        });
      };

      updatePlacement();
      window.addEventListener("resize", handleUpdate);
      window.addEventListener("scroll", handleUpdate, true);

      return () => {
        window.removeEventListener("resize", handleUpdate);
        window.removeEventListener("scroll", handleUpdate, true);
        if (frame !== null) cancelAnimationFrame(frame);
      };
    }, [isOpen]);

    const handleDateStringChange = (value) => {
      if (value === null) {
        setSelectedDate(null);
        setInputValue("");
        return;
      }

      if (moment.isMoment(value)) {
        // Validate against min/max dates
        if (minDate && value.isBefore(minDate, "day")) {
          setInputValue(value.format(displayFormat));
          setSelectedDate(null);
          return;
        }
        if (maxDate && value.isAfter(maxDate, "day")) {
          setInputValue(value.format(displayFormat));
          setSelectedDate(null);
          return;
        }
        setSelectedDate(value);
        setInputValue(value.format(displayFormat));
      } else {
        // If it's a string, check if it's a complete date
        const parsedDate = moment(value, displayFormat, true);
        if (parsedDate.isValid()) {
          // Validate against min/max dates
          if (minDate && parsedDate.isBefore(minDate, "day")) {
            setInputValue(value);
            setSelectedDate(null);
            return;
          }
          if (maxDate && parsedDate.isAfter(maxDate, "day")) {
            setInputValue(value);
            setSelectedDate(null);
            return;
          }
          setSelectedDate(parsedDate);
        }
        setInputValue(value);
      }
    };

    const handleClear = () => {
      setSelectedDate(null);
      setInputValue("");
      setCancelTrigger((prev) => prev + 1);
      onTertiaryButtonClick?.();
      // Force a re-render of the calendar by updating focused state
      setFocused(false);
      setTimeout(() => setFocused(true), 0);
    };

    const handleCancel = () => {
      setIsOpen(false);
      onSecondaryButtonClick?.();
    };

    const handleClickOutside = (event) => {
      const isWithinMainContainer =
        datePickerMainContainerRef.current &&
        datePickerMainContainerRef.current.contains(event.target);

      const isWithinPortalContainer =
        withPortal && event.target.closest(".impact-portal-container");

      const isWithinButtonsContainer = event.target.closest(
        ".datePicker-buttons-container"
      );

      if (
        !isWithinMainContainer &&
        !isWithinPortalContainer &&
        !isWithinButtonsContainer &&
        !isAgGridCellRenderer &&
        !event.target.closest(".ia-select-container-v3-styled-menu ") &&
        isOpen
      ) {
        onClickOutside?.();
        setIsOpen(false);
      }
    };

    useEffect(() => {
      setFocused(isOpen);
      document.addEventListener("mousedown", handleClickOutside);

      return () => {
        document.removeEventListener("mousedown", handleClickOutside);
      };
    }, [isOpen]);

    const onDatesChange = (date) => {
      if (handleDateChange) {
        handleDateChange(date);
      } else {
        setSelectedDate(date);
      }
      closeOnDateSelect && setIsOpen(false);
    };

    // Compute error state if selectedDate is out of range
    const computedIsError = useMemo(
      () =>
        Boolean(isError || (selectedDate && isOutsideRange?.(selectedDate))),
      [isError, selectedDate]
    );

    return (
      <div
        className={`impact-datepicker-main-container ${
          labelOrientation === "left" ? "label-flex-row" : "label-flex-column"
        } ${fullWidth ? "impact-datepicker-full-width-main-container" : ""}`}
      >
        {label && (
          <div className="datePicker-label">
            {label} {isRequired && <span style={{ color: "red" }}>*</span>}
          </div>
        )}
        <div className="datePicker-container" ref={datePickerMainContainerRef}>
          <DatePickerInput
            readOnly={args?.readOnly}
            dateString={inputValue}
            placeholder={placeholder}
            isError={computedIsError}
            isDisabled={isDisabled}
            inputContainerRef={inputContainerRef}
            selectedDate={selectedDate}
            isOpen={isOpen}
            setIsOpen={setIsOpen}
            ref={ref}
            inputProps={inputProps}
            displayFormat={displayFormat}
            onDateStringChange={handleDateStringChange}
            minDate={minDate}
            maxDate={maxDate}
            onCancel={cancelTrigger}
            customIcon={customIcon}
          />
          {isOpen && (
            <DatePickerDropdown
              {...args}
              onDatesChange={onDatesChange}
              focused={focused}
              setFocused={setFocused}
              selectedDate={selectedDate}
              setSelectedDate={setSelectedDate}
              showWeekNumbers={showWeekNumbers}
              primaryButtonProps={primaryButtonProps}
              secondaryButtonProps={secondaryButtonProps}
              tertiaryButtonProps={tertiaryButtonProps}
              onPrimaryButtonClick={onPrimaryButtonClick}
              onSecondaryButtonClick={handleCancel}
              onTertiaryButtonClick={handleClear}
              setIsOpen={setIsOpen}
              withPortal={withPortal}
              portalContainer={portalContainer}
              containerRef={datePickerMainContainerRef}
              showMonthYearSelect={showMonthYearSelect}
              customYears={customYears}
              minDate={minDate}
              maxDate={maxDate}
              isOutsideRange={isOutsideRange}
              placement={placement}
              hideSecondaryButton={hideSecondaryButton}
              hideTertiaryButton={hideTertiaryButton}
              hidePrimaryButton={hidePrimaryButton}
              dropdownRef={dropdownRef}
              allButtonsHidden={allButtonsHidden}
            />
          )}
        </div>
      </div>
    );
  }
);
