import { useEffect, useMemo, useState, type CSSProperties, type RefObject } from 'react';
import { createPortal } from 'react-dom';

import {
  QUARTER_RANGE_LABELS,
  buildMonthWeekRows,
  dateToQuarter,
  isSameDay,
  isSameWeek,
  quarterEndDate,
  startOfDay,
  startOfWeekMonday,
  toIsoDate,
} from '../../lib/boardCalendar';

const WEEKDAY_LABELS = ['월', '화', '수', '목', '금', '토', '일'];

interface BoardCalendarPopoverProps {
  referenceDate: Date;
  onChange: (d: Date) => void;
  onClose: () => void;
  anchorRef: RefObject<HTMLElement | null>;
}

export function BoardCalendarPopover({
  referenceDate,
  onChange,
  onClose,
  anchorRef,
}: BoardCalendarPopoverProps) {
  const [viewYear, setViewYear] = useState(referenceDate.getFullYear());
  const [viewMonth, setViewMonth] = useState(referenceDate.getMonth());

  const weekRows = useMemo(
    () => buildMonthWeekRows(viewYear, viewMonth),
    [viewYear, viewMonth],
  );

  const activeQuarterKey = dateToQuarter(referenceDate);

  useEffect(() => {
    setViewYear(referenceDate.getFullYear());
    setViewMonth(referenceDate.getMonth());
  }, [referenceDate]);

  useEffect(() => {
    const onPointerDown = (e: MouseEvent) => {
      const anchor = anchorRef.current;
      const target = e.target as Node;
      if (anchor?.contains(target)) return;
      const popover = document.getElementById('board-calendar-popover');
      if (popover?.contains(target)) return;
      onClose();
    };
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose();
    };
    document.addEventListener('mousedown', onPointerDown);
    document.addEventListener('keydown', onKeyDown);
    return () => {
      document.removeEventListener('mousedown', onPointerDown);
      document.removeEventListener('keydown', onKeyDown);
    };
  }, [anchorRef, onClose]);

  const rect = anchorRef.current?.getBoundingClientRect();
  const style: CSSProperties = rect
    ? { top: rect.bottom + 8, right: Math.max(12, window.innerWidth - rect.right) }
    : { top: 56, right: 24 };

  const shiftMonth = (delta: number) => {
    const d = new Date(viewYear, viewMonth + delta, 1);
    setViewYear(d.getFullYear());
    setViewMonth(d.getMonth());
  };

  const pickDate = (d: Date) => {
    onChange(startOfDay(d));
  };

  const pickQuarter = (q: 1 | 2 | 3 | 4) => {
    onChange(quarterEndDate(`${viewYear}-Q${q}`));
  };

  const today = startOfDay(new Date());

  return createPortal(
    <div id="board-calendar-popover" className="board-calendar-popover" style={style} role="dialog" aria-label="기준일 선택">
      <div className="board-calendar-popover-head">
        <button type="button" className="board-calendar-nav" onClick={() => shiftMonth(-1)} aria-label="이전 달">‹</button>
        <span className="board-calendar-month">{viewYear}년 {viewMonth + 1}월</span>
        <button type="button" className="board-calendar-nav" onClick={() => shiftMonth(1)} aria-label="다음 달">›</button>
      </div>

      <div className="board-calendar-quarter-row">
        {([1, 2, 3, 4] as const).map((q) => {
          const key = `${viewYear}-Q${q}`;
          const selected = activeQuarterKey === key;
          return (
            <button
              key={key}
              type="button"
              className={`board-calendar-quarter-chip${selected ? ' is-selected' : ''}`}
              onClick={() => pickQuarter(q)}
            >
              <span className="board-calendar-quarter-chip-title">{q}분기</span>
              <span className="board-calendar-quarter-chip-range">{QUARTER_RANGE_LABELS[q - 1]}</span>
            </button>
          );
        })}
      </div>

      <div className="board-calendar-grid-wrap">
        <table className="board-calendar-grid">
          <thead>
            <tr>
              <th className="board-calendar-grid-week-col">주차</th>
              {WEEKDAY_LABELS.map((label) => (
                <th key={label}>{label}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {weekRows.map((row) => {
              const weekSelected = isSameWeek(referenceDate, row.monday);
              return (
                <tr key={toIsoDate(row.monday)} className={weekSelected ? 'is-selected-week' : undefined}>
                  <td className="board-calendar-grid-week-col">
                    <button
                      type="button"
                      className="board-calendar-week-label-btn"
                      onClick={() => pickDate(startOfWeekMonday(row.monday))}
                    >
                      {row.label}
                    </button>
                  </td>
                  {row.days.map((day) => {
                    const inMonth = day.getMonth() === viewMonth;
                    const isRef = isSameDay(day, referenceDate);
                    const isToday = isSameDay(day, today);
                    return (
                      <td key={toIsoDate(day)}>
                        <button
                          type="button"
                          className={[
                            'board-calendar-day-btn',
                            !inMonth ? 'is-outside' : '',
                            isRef ? 'is-ref' : '',
                            isToday ? 'is-today' : '',
                          ].filter(Boolean).join(' ')}
                          onClick={() => pickDate(day)}
                        >
                          {day.getDate()}
                        </button>
                      </td>
                    );
                  })}
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      <div className="board-calendar-foot">
        <button type="button" onClick={() => pickDate(startOfWeekMonday(today))}>이번 주</button>
        <button type="button" onClick={() => pickDate(today)}>이번 분기</button>
      </div>
    </div>,
    document.body,
  );
}
