import React, { useEffect, useState, useRef, useLayoutEffect } from "react";

import { monthsNumber } from "./constant";
import ChevronLeftOutlinedIcon from "@mui/icons-material/ChevronLeftOutlined";
import ChevronRightOutlinedIcon from "@mui/icons-material/ChevronRightOutlined";
import "./MonthRangePicker.styles.scss";
import { Select } from "../Select";
import { Button } from "../Button";
import { IconButton } from "@mui/material";
import { ReactComponent as CloseIcon } from "../../assets/close.svg";
import Portal from "../Portal";

export const MonthRangePicker = ({
  customYears,
  locale = "en-US",
  isMandatory = false,
  displayFormat = "MM/YYYY",
  focusedInput = null,
  onApply = () => {},
  startMonth: initialStartMonth = null,
  endMonth: initialEndMonth = null,
  showYearSelect = false,
  isOutsideRange = () => false,
  disabled = false,
  customWidth = "282px",
  isError = false,
  withPortal = false,
  portalContainer = document.body,
  portalClassName = "",
  onStartMonthChange = () => {},
  onEndMonthChange = () => {},
}) => {
  const today = new Date();
  const currentYear = today.getFullYear();
  const yrs = Array.from({ length: 10 }, (_, index) => {
    const year = (currentYear - 5 + index).toString();
    return { label: year, value: year };
  });

  const years = customYears && customYears.length > 0 ? customYears : yrs;

  const [openCalendar, setOpenCalendar] = useState(false);
  const [startMonth, setStartMonth] = useState(initialStartMonth);
  const [endMonth, setEndMonth] = useState(initialEndMonth);
  const [yearOffset, setYearOffset] = useState(0);
  const [open1, setOpen1] = useState(false);
  const [currentOptions1, setCurrentOptions1] = useState(years);
  const [selectedOptions1, setSelectedOptions1] = useState({
    label: (today.getFullYear() - 1).toString(),
    value: (today.getFullYear() - 1).toString(),
  });
  const [open2, setOpen2] = useState(false);
  const [currentOptions2, setCurrentOptions2] = useState(years);
  const [selectedOptions2, setSelectedOptions2] = useState({
    label: today.getFullYear().toString(),
    value: today.getFullYear().toString(),
  });
  const inputContainerRef = useRef(null);
  const dropDownContainerRef = useRef(null);
  const dropDownRef = useRef(null);
  const startDateInputRef = useRef();
  const endDateInputRef = useRef();
  const monthRangePickerMainContainerRef = useRef(null);
  const [isSelectOpen, setIsSelectOpen] = useState(false);
  const [focusInput, setFocusInput] = useState(focusedInput);
  const [dummyStartMonth, setDummyStartMonth] = useState(initialStartMonth);
  const [dummyEndMonth, setDummyEndMonth] = useState(initialEndMonth);
  const isResetClicked = useRef(false);
  const [prevIconDisabled, setPrevIconDisabled] = useState(false);
  const [nextIconDisabled, setNextIconDisabled] = useState(false);
  const [hoveredMonth, setHoveredMonth] = useState(null);
  const [position, setPosition] = useState({
    x: 0,
    y: 0,
    offsetHeight: 0,
    offsetWidth: 0,
  });
  const [focusedPanel, setFocusedPanel] = useState(1);
  const [focusedMonthIndex, setFocusedMonthIndex] = useState(null);
  const panel1ButtonRefs = useRef([]);
  const panel2ButtonRefs = useRef([]);
  const keyboardOpenRef = useRef(false);
  const pendingFocusRef = useRef(null);

  const isMonthSelected = (month) => {
    if (!startMonth) {
      return false;
    }

    // If we have both start and end month, use the actual selection
    if (endMonth) {
      const startYearMonth =
        startMonth.getFullYear() * 12 + startMonth.getMonth();
      const endYearMonth = endMonth.getFullYear() * 12 + endMonth.getMonth();
      const currentYearMonth = month.getFullYear() * 12 + month.getMonth();
      return (
        currentYearMonth >= startYearMonth && currentYearMonth <= endYearMonth
      );
    }

    // If we only have start month and we're hovering over another month, show preview
    if (hoveredMonth && !endMonth) {
      const startYearMonth =
        startMonth.getFullYear() * 12 + startMonth.getMonth();
      const hoveredYearMonth =
        hoveredMonth.getFullYear() * 12 + hoveredMonth.getMonth();
      const currentYearMonth = month.getFullYear() * 12 + month.getMonth();

      const minMonth = Math.min(startYearMonth, hoveredYearMonth);
      const maxMonth = Math.max(startYearMonth, hoveredYearMonth);

      return currentYearMonth >= minMonth && currentYearMonth <= maxMonth;
    }

    return false;
  };

  const isMonthStart = (month) => {
    return month.getTime() === (startMonth?.getTime() || 0);
  };

  const isMonthEnd = (month) => {
    if (!endMonth) {
      return false;
    }

    const endYearMonth = endMonth.getFullYear() * 12 + endMonth.getMonth();
    const currentYearMonth = month.getFullYear() * 12 + month.getMonth();

    return currentYearMonth === endYearMonth;
  };

  const handleMonthClick = (month, type) => {
    const MIN_RANGE = 0;
    const MAX_RANGE = null;

    const monthsDiff = (m1, m2) => Math.abs(m1 - m2);

    if (!startMonth && !endMonth) {
      setStartMonth(month);
      onStartMonthChange(month);
      setFocusInput("end month");
      return;
    }

    if (startMonth && !endMonth) {
      if (month === startMonth) {
        setStartMonth(null);
        onStartMonthChange(null);
        setFocusInput("end month");
        return;
      }

      if (month < startMonth) {
        if (monthsDiff(month, startMonth) < MIN_RANGE) return;
        if (MAX_RANGE && monthsDiff(month, startMonth) > MAX_RANGE) return;

        setEndMonth(startMonth);
        onEndMonthChange(startMonth);
        setStartMonth(month);
        onStartMonthChange(month);
        setFocusInput("start month");
        return;
      }

      if (monthsDiff(month, startMonth) < MIN_RANGE) return;
      if (MAX_RANGE && monthsDiff(month, startMonth) > MAX_RANGE) return;
      setEndMonth(month);
      onEndMonthChange(month);
      setFocusInput("start month");
      return;
    }

    if (startMonth && endMonth) {
      setStartMonth(month);
      onStartMonthChange(month);
      setEndMonth(null);
      onEndMonthChange(null);
      setFocusInput("end month");
      return;
    }
  };

  const formatDate = (date) => {
    if (!date) return "";

    const month = new Intl.DateTimeFormat("en-US", { month: "2-digit" }).format(
      date
    );
    const year = new Intl.DateTimeFormat("en-US", { year: "numeric" }).format(
      date
    );

    if (displayFormat === "YYYY/MM") {
      return `${year}/${month}`;
    }
    // Default to MM/YYYY format
    return `${month}/${year}`;
  };

  const handleMonthHover = (month) => {
    if (startMonth && !endMonth) {
      setHoveredMonth(month);
    }
  };

  const handleMonthLeave = () => {
    setHoveredMonth(null);
  };

  const renderMonth = (year, type, month) => {
    const monthStart = new Date(year, month, 1);
    const isSelected = isMonthSelected(monthStart);
    const isStart = isMonthStart(monthStart);
    const isEnd = isMonthEnd(monthStart);
    const isDisabled = isOutsideRange(monthStart);
    const isCurrentMonth =
      monthStart.getFullYear() === today.getFullYear() &&
      monthStart.getMonth() === today.getMonth();

    // Check if hovered month is previous to end month for styling direction
    const isHoveredPreviousToEnd =
      hoveredMonth &&
      startMonth &&
      hoveredMonth.getFullYear() * 12 + hoveredMonth.getMonth() <
        startMonth.getFullYear() * 12 + startMonth.getMonth();

    const getVariants = () => {
      if (isStart) return "start";
      if (isEnd) return "end";
      if (isSelected) return "selected";
      return "";
    };

    const panel = type === "start" ? 1 : 2;
    const panelRefs = panel === 1 ? panel1ButtonRefs : panel2ButtonRefs;
    const isFocused = focusedPanel === panel && focusedMonthIndex === month;

    return (
      <button
        key={month}
        type="button"
        className={`ia-month month${month + 1} ${getVariants()} ${
          startMonth && getVariants() === "end" ? "has-start-month" : ""
        } ${isCurrentMonth ? "current-month" : ""} ${
          isHoveredPreviousToEnd ? "hovered-previous-to-end" : ""
        } ${isDisabled ? "disabled" : ""}`}
        tabIndex={isFocused ? 0 : -1}
        ref={(el) => (panelRefs.current[month] = el)}
        disabled={isDisabled}
        onClick={() => handleMonthClick(monthStart, type)}
        onMouseEnter={() => !isDisabled && handleMonthHover(monthStart)}
        onMouseLeave={handleMonthLeave}
        onFocus={() => {
          setFocusedPanel(panel);
          setFocusedMonthIndex(month);
        }}
        aria-label={new Intl.DateTimeFormat(locale, {
          month: "long",
          year: "numeric",
        }).format(monthStart)}
        aria-pressed={isStart || isEnd || isSelected}
      >
        <span className="ia-calendar-month">
          {new Intl.DateTimeFormat(locale, { month: "short" }).format(
            monthStart
          )}
        </span>
      </button>
    );
  };

  const renderYear = (year, type) => (
    <div className="ia-render-month">
      {monthsNumber.map((month) => renderMonth(year, type, month))}
    </div>
  );

  const handlePrevYear = () => {
    const offset = yearOffset - 1;

    setYearOffset(offset);
    setSelectedOptions1((prevState) => {
      const newValue = parseInt(prevState.value) - 1;
      if (newValue == currentOptions1[0].value) {
        setPrevIconDisabled(true);
      }
      return { label: newValue.toString(), value: newValue.toString() };
    });

    setSelectedOptions2((prevState) => {
      const newValue = parseInt(prevState.value) - 1;
      return { label: newValue.toString(), value: newValue.toString() };
    });
  };

  const handleNextYear = () => {
    const offset = yearOffset + 1;

    setYearOffset(offset);
    setSelectedOptions1((prevState) => {
      const newValue = parseInt(prevState.value) + 1;
      return { label: newValue.toString(), value: newValue.toString() };
    });

    setSelectedOptions2((prevState) => {
      const newValue = parseInt(prevState.value) + 1;
      if (newValue == currentOptions2[currentOptions2.length - 1].value) {
        setNextIconDisabled(true);
      }
      return { label: newValue.toString(), value: newValue.toString() };
    });
  };

  const handleYearSelect = (selectId, selectedValue) => {
    const newYear = parseInt(selectedValue.value);

    if (selectId === 1) {
      // Ensure a 1-year difference
      setSelectedOptions1({
        label: newYear.toString(),
        value: newYear.toString(),
      });
      setSelectedOptions2({
        label: (newYear + 1).toString(),
        value: (newYear + 1).toString(),
      });
    } else if (selectId === 2) {
      setSelectedOptions2({
        label: newYear.toString(),
        value: newYear.toString(),
      });
      setSelectedOptions1({
        label: (newYear - 1).toString(),
        value: (newYear - 1).toString(),
      });
    }
    setIsSelectOpen(true);
  };

  const hanldeInputClick = (inputType) => {
    setOpenCalendar(true);
    setFocusInput(inputType);
  };

  const handleInputKeyDown = (e) => {
    if (e.key === "Enter" && !openCalendar) {
      keyboardOpenRef.current = true;
      hanldeInputClick("start month");
      setFocusedPanel(1);
      setFocusedMonthIndex(startMonth?.getMonth() ?? 0);
    }
  };

  const handleCalendarKeyDown = (e) => {
    if (e.key === "Escape") {
      handleCancel();
      startDateInputRef.current?.focus();
      return;
    }
    const moves = { ArrowRight: 1, ArrowLeft: -1, ArrowDown: 4, ArrowUp: -4 };
    if (moves[e.key] === undefined || focusedMonthIndex === null) return;
    e.preventDefault();
    const delta = moves[e.key];
    let newPanel = focusedPanel;
    let newIndex = focusedMonthIndex + delta;

    if (focusedPanel === 1) {
      if (newIndex > 11) {
        // Cross to panel 2 (same year pair, no year nav needed)
        newPanel = 2;
        newIndex = newIndex - 12;
      } else if (newIndex < 0) {
        // Go to previous year, stay in panel 1
        if (!prevIconDisabled) {
          pendingFocusRef.current = { panel: 1, index: newIndex + 12 };
          handlePrevYear();
        }
        return;
      }
    } else {
      // focusedPanel === 2
      if (newIndex > 11) {
        // Go to next year, stay in panel 2
        if (!nextIconDisabled) {
          pendingFocusRef.current = { panel: 2, index: newIndex - 12 };
          handleNextYear();
        }
        return;
      } else if (newIndex < 0) {
        // Cross back to panel 1 (same year pair, no year nav needed)
        newPanel = 1;
        newIndex = newIndex + 12;
      }
    }

    setFocusedPanel(newPanel);
    setFocusedMonthIndex(newIndex);

    const refs = newPanel === 1 ? panel1ButtonRefs : panel2ButtonRefs;
    refs.current[newIndex]?.focus();

    const year =
      newPanel === 1
        ? parseInt(selectedOptions1.value)
        : parseInt(selectedOptions2.value);
    if (startMonth && !endMonth) {
      setHoveredMonth(new Date(year, newIndex, 1));
    }
  };

  useEffect(() => {
    if (focusInput === "start month") {
      startDateInputRef.current.focus();
    }
    if (focusInput === "end month") {
      endDateInputRef.current.focus();
    }
  }, [focusInput]);

  useEffect(() => {
    if (openCalendar && keyboardOpenRef.current && focusedMonthIndex !== null) {
      const timer = setTimeout(() => {
        panel1ButtonRefs.current[focusedMonthIndex]?.focus();
      }, 0);
      keyboardOpenRef.current = false;
      return () => clearTimeout(timer);
    }
  }, [openCalendar]);

  useEffect(() => {
    if (pendingFocusRef.current !== null) {
      const { panel, index } = pendingFocusRef.current;
      pendingFocusRef.current = null;
      setFocusedPanel(panel);
      setFocusedMonthIndex(index);
      setTimeout(() => {
        const refs = panel === 1 ? panel1ButtonRefs : panel2ButtonRefs;
        refs.current[index]?.focus();
      }, 0);
    }
  }, [selectedOptions1, selectedOptions2]);
  const handleClickOutside = (event) => {
    if (
      inputContainerRef.current &&
      !inputContainerRef.current.contains(event.target) &&
      dropDownContainerRef.current &&
      !dropDownContainerRef.current.contains(event.target) &&
      !event.target.closest(".close-icon") &&
      !event.target.closest(".month-range-picker-year-select-dropdown") &&
      !isSelectOpen
    ) {
      setOpenCalendar(false);
      if (isResetClicked.current) {
        setStartMonth(null);
        setEndMonth(null);
        setDummyStartMonth(null);
        setDummyEndMonth(null);
        isResetClicked.current = false;
      } else {
        setStartMonth(dummyStartMonth);
        setEndMonth(dummyEndMonth);
      }
    }
  };

  useEffect(() => {
    document.addEventListener("click", handleClickOutside);

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

  const handleClear = () => {
    setStartMonth(null);
    setEndMonth(null);
    setDummyStartMonth(null);
    setDummyEndMonth(null);
    isResetClicked.current = true;
  };

  const handleCancel = () => {
    setOpenCalendar(false);
    setStartMonth(dummyStartMonth);
    setEndMonth(dummyEndMonth);
  };

  const handleApply = () => {
    setOpenCalendar(false);
    setDummyStartMonth(startMonth);
    setDummyEndMonth(endMonth);
    onApply?.(startMonth, endMonth);
  };

  // Calculate position for portal
  useLayoutEffect(() => {
    if (withPortal && monthRangePickerMainContainerRef.current) {
      const scrollY = window.scrollY || document.documentElement.scrollTop;
      const {
        x,
        y,
        height: offsetHeight,
        width: offsetWidth,
      } = monthRangePickerMainContainerRef.current.getBoundingClientRect();
      setPosition({ x, y: y + scrollY, offsetHeight, offsetWidth });
    }
  }, [openCalendar, withPortal]);

  useEffect(() => {
    if (selectedOptions1.value == currentOptions1[0].value) {
      setPrevIconDisabled(true);
    } else {
      setPrevIconDisabled(false);
    }
    if (
      selectedOptions2.value ==
      currentOptions2[currentOptions2.length - 1].value
    ) {
      setNextIconDisabled(true);
    } else {
      setNextIconDisabled(false);
    }
  }, [selectedOptions1, selectedOptions2]);

  const renderCalendarContent = () => (
    <div
      className="ia-month-picker-container"
      ref={dropDownContainerRef}
      onKeyDown={handleCalendarKeyDown}
      role="dialog"
      aria-label="Month range picker"
    >
      <div className="ia-header">
        <IconButton
          onClick={handlePrevYear}
          disableRipple
          disabled={prevIconDisabled}
        >
          <ChevronLeftOutlinedIcon className="left-icon" />
        </IconButton>
        {showYearSelect ? (
          <div className="month-range-picker-year-select-container">
            <Select
              name="year-select"
              isWithSearch
              withPortal
              dropDownPortalClassName={
                "month-range-picker-year-select-dropdown"
              }
              isOpen={open1}
              setIsOpen={setOpen1}
              currentOptions={currentOptions1}
              setCurrentOptions={setCurrentOptions1}
              initialOptions={years}
              selectedOptions={selectedOptions1}
              setSelectedOptions={setSelectedOptions1}
              handleChange={(val) => handleYearSelect(1, val)}
              ref={dropDownRef}
              minWidth={100}
            />
          </div>
        ) : (
          <div className="month-range-picker-selected-year">
            {selectedOptions1.value}
          </div>
        )}
        {showYearSelect ? (
          <div className="month-range-picker-year-select-container">
            <Select
              name="month-select"
              isWithSearch
              withPortal
              dropDownPortalClassName={
                "month-range-picker-year-select-dropdown"
              }
              isOpen={open2}
              setIsOpen={setOpen2}
              currentOptions={currentOptions2}
              setCurrentOptions={setCurrentOptions2}
              initialOptions={years}
              selectedOptions={selectedOptions2}
              setSelectedOptions={setSelectedOptions2}
              handleChange={(val) => handleYearSelect(2, val)}
              minWidth={100}
            />
          </div>
        ) : (
          <div className="month-range-picker-selected-year">
            {selectedOptions2.value}
          </div>
        )}
        <IconButton
          onClick={handleNextYear}
          disableRipple
          disabled={nextIconDisabled}
        >
          <ChevronRightOutlinedIcon className="right-icon" />
        </IconButton>
      </div>
      <div className="ia-render-month-container">
        {renderYear(parseInt(selectedOptions1.value), "start")}
        <hr className="ia-vertical-line" />
        {renderYear(parseInt(selectedOptions2.value), "end")}
      </div>
      <hr className="ia-vertical-line" />
      <div className="ia-calendar-button">
        <Button variant="tertiary" onClick={handleCancel}>
          Cancel
        </Button>
        <Button onClick={handleApply}>Apply</Button>
      </div>
    </div>
  );

  return (
    <div
      className={`impact-monthRangePicker-main-container label-flex-column ${
        disabled ? "disabled" : ""
      }`}
    >
      <div className="monthRangePicker-label">
        Select Month & Year
        {isMandatory && <span style={{ color: "red" }}>*</span>}
      </div>

      <div
        className="monthRangePicker-container"
        style={{ width: customWidth }}
        ref={monthRangePickerMainContainerRef}
      >
        <div
          className="monthRangePicker-input-container"
          ref={inputContainerRef}
        >
          <input
            type="text"
            placeholder={`Start ${displayFormat} - `}
            readOnly
            className={`dateRangePicker-input-start-date ${
              startMonth ? "active" : ""
            } ${isError ? "error" : ""}`}
            value={startMonth ? `${formatDate(startMonth)} -` : ""}
            ref={startDateInputRef}
            onClick={() => hanldeInputClick("start month")}
            onFocus={() => setFocusInput("start month")}
            onKeyDown={handleInputKeyDown}
            aria-label="Start month"
            aria-haspopup="dialog"
            aria-expanded={openCalendar}
          />
          <input
            type="text"
            placeholder={`End ${displayFormat}`}
            label="EndDate"
            name="endDate"
            readOnly
            className={`dateRangePicker-input-end-date ${
              isError ? "error" : ""
            }`}
            value={endMonth ? formatDate(endMonth) : ""}
            ref={endDateInputRef}
            onClick={() => hanldeInputClick("end month")}
            onFocus={() => setFocusInput("end month")}
            onKeyDown={handleInputKeyDown}
            aria-label="End month"
            aria-haspopup="dialog"
            aria-expanded={openCalendar}
          />
          {(startMonth || endMonth) && (
            <CloseIcon 
              className="close-icon" 
              onClick={handleClear} 
              aria-label="Close month range picker"
              tabIndex={0}
              onKeyDown={(e) => {
                if (e.key === "Enter" || e.key === " ") {
                  e.preventDefault();
                  handleClear();
                }
              }}
            />
          )}
        </div>
        {openCalendar &&
          (withPortal ? (
            <Portal container={portalContainer}>
              <div
                className={`impact-portal-container ${portalClassName}`}
                style={{
                  top: position.y || position.top,
                  left: position.x || position.left,
                  bottom: position.bottom,
                  right: position.right,
                  width: position.offsetWidth || 0 + "px",
                }}
              >
                {renderCalendarContent()}
              </div>
              <div
                className="ia-select-container-v3-blanket"
                onClick={() => setOpenCalendar(false)}
              />
            </Portal>
          ) : (
            renderCalendarContent()
          ))}
      </div>
    </div>
  );
};
