import { useMemo, useState, type ReactNode } from "react";
import { Link } from "react-router-dom";
import type { CalendarEvent } from "../lib/api";
import {
  calendarEventShortLabel,
  calendarRangeFromToday,
  categoryTip,
  impactClass,
  impactLabel,
} from "../lib/calendarInfo";
import { Explain, Tag } from "./ui";

const WEEKDAYS = ["日", "一", "二", "三", "四", "五", "六"] as const;
const IMPACT_RANK: Record<string, number> = { high: 0, medium: 1, low: 2 };

function sortDayEvents(list: CalendarEvent[]) {
  return [...list].sort((a, b) => {
    const ra = IMPACT_RANK[a.impact || ""] ?? 2;
    const rb = IMPACT_RANK[b.impact || ""] ?? 2;
    if (ra !== rb) return ra - rb;
    return String(a.titleZh || a.title).localeCompare(String(b.titleZh || b.title));
  });
}

function formatDayLabel(iso: string) {
  const d = new Date(`${iso}T12:00:00`);
  if (Number.isNaN(d.getTime())) return iso;
  return d.toLocaleDateString("zh-TW", { month: "long", day: "numeric", weekday: "long" });
}

function isoFromParts(y: number, m: number, day: number) {
  return `${y}-${String(m + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
}

function chipClass(ev: CalendarEvent) {
  const cat = ev.category || "macro";
  const imp = ev.impact || "low";
  return `cal-ev ${imp} cat-${cat}`;
}

function dotClass(ev: CalendarEvent) {
  const cat = ev.category || "macro";
  const imp = ev.impact || "low";
  return `cal-dot ${imp} cat-${cat}`;
}

function CalendarDayDetail({ date, events }: { date: string; events: CalendarEvent[] }) {
  return (
    <div className="cal-day-panel">
      <div className="cal-day-detail-head">
        <b>{formatDayLabel(date)}</b>
        <span>{events.length} 項事件</span>
      </div>
      {!events.length ? (
        <p className="muted small cal-day-empty">這天沒有事件。點其他日期格子查看。</p>
      ) : (
        <div className="cal-detail-list">
          {events.map((ev, i) => {
            const ci = categoryTip(ev.category);
            return (
              <div className={`cal-detail-row ${ev.impact || "low"}`} key={`${ev.title}-${i}`}>
                <div className="cal-detail-main">
                  <div className="cal-detail-title">
                    <span className={`event-impact ${ev.impact || "low"}`}>
                      {impactLabel(ev.impact).slice(0, 1)}
                    </span>
                    <b>{ev.titleZh || ev.title}</b>
                    {ev.symbol && (
                      <Link to={`/research?sym=${encodeURIComponent(ev.symbol)}`} className="event-symbol">
                        {ev.symbol}
                      </Link>
                    )}
                    <Tag>{ci?.label}</Tag>
                    <span className={"tag " + impactClass(ev.impact)}>{impactLabel(ev.impact)}</span>
                    <Explain tip={ci?.tip} label={`${ci?.label}・這天會公布什麼`} />
                  </div>
                  <div className="cal-detail-note">
                    {ev.note || "—"}
                    {ev.time ? ` · ${ev.time}` : ""}
                  </div>
                </div>
                <div className="cal-detail-meta">
                  {ci?.label}
                  {ev.source ? <small>{ev.source}</small> : null}
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

export default function CalendarBoard({
  events,
  portfolioCount = 0,
  start: startIn,
  end: endIn,
}: {
  events: CalendarEvent[];
  portfolioCount?: number;
  start?: string;
  end?: string;
}) {
  const fallback = calendarRangeFromToday(60);
  const range = {
    start: startIn || fallback.start,
    end: endIn || fallback.end,
    today: fallback.today,
  };

  const todayDate = useMemo(() => new Date(`${range.today}T12:00:00`), [range.today]);
  const [viewMonth, setViewMonth] = useState(() => ({
    y: todayDate.getFullYear(),
    m: todayDate.getMonth(),
  }));
  const [selectedDate, setSelectedDate] = useState<string>(range.today);

  const byDate = useMemo(() => {
    const map = new Map<string, CalendarEvent[]>();
    for (const ev of events) {
      if (ev.date < range.start || ev.date > range.end) continue;
      const list = map.get(ev.date) || [];
      list.push(ev);
      map.set(ev.date, list);
    }
    for (const [k, list] of map) map.set(k, sortDayEvents(list));
    return map;
  }, [events, range.start, range.end]);

  const monthBounds = useMemo(() => {
    const start = new Date(`${range.start}T12:00:00`);
    const end = new Date(`${range.end}T12:00:00`);
    return {
      minY: start.getFullYear(),
      minM: start.getMonth(),
      maxY: end.getFullYear(),
      maxM: end.getMonth(),
    };
  }, [range.start, range.end]);

  const canPrev = useMemo(() => {
    const { minY, minM } = monthBounds;
    return viewMonth.y > minY || (viewMonth.y === minY && viewMonth.m > minM);
  }, [monthBounds, viewMonth]);

  const canNext = useMemo(() => {
    const { maxY, maxM } = monthBounds;
    return viewMonth.y < maxY || (viewMonth.y === maxY && viewMonth.m < maxM);
  }, [monthBounds, viewMonth]);

  const selectedEvents = byDate.get(selectedDate) || [];
  const eventCount = useMemo(() => {
    let n = 0;
    for (const [, list] of byDate) n += list.length;
    return n;
  }, [byDate]);

  const viewMonthLabel = useMemo(() => {
    const d = new Date(viewMonth.y, viewMonth.m, 1);
    return d.toLocaleDateString("zh-TW", { year: "numeric", month: "long" });
  }, [viewMonth]);

  const goPrevMonth = () => {
    if (!canPrev) return;
    setViewMonth((v) => (v.m === 0 ? { y: v.y - 1, m: 11 } : { y: v.y, m: v.m - 1 }));
  };

  const goNextMonth = () => {
    if (!canNext) return;
    setViewMonth((v) => (v.m === 11 ? { y: v.y + 1, m: 0 } : { y: v.y, m: v.m + 1 }));
  };

  const goToday = () => {
    setSelectedDate(range.today);
    setViewMonth({ y: todayDate.getFullYear(), m: todayDate.getMonth() });
  };

  const { y, m } = viewMonth;
  const firstDow = new Date(y, m, 1).getDay();
  const daysInMonth = new Date(y, m + 1, 0).getDate();
  const cells: ReactNode[] = [];

  for (let i = 0; i < firstDow; i++) {
    cells.push(<div key={`pad-${y}-${m}-${i}`} className="cal-cell pad" />);
  }

  for (let day = 1; day <= daysInMonth; day++) {
    const iso = isoFromParts(y, m, day);
    const inRange = iso >= range.start && iso <= range.end;
    const dayEvents = byDate.get(iso) || [];
    const cls = [
      "cal-cell",
      inRange ? "in-range" : "off",
      iso === range.today ? "today" : "",
      selectedDate === iso ? "selected" : "",
      dayEvents.length ? "has-events" : "",
      dayEvents.some((e) => e.impact === "high") ? "has-hot" : "",
    ]
      .filter(Boolean)
      .join(" ");

    cells.push(
      <button
        key={iso}
        type="button"
        className={cls}
        disabled={!inRange}
        aria-label={`${iso}，${dayEvents.length} 項事件`}
        aria-pressed={selectedDate === iso}
        onClick={() => inRange && setSelectedDate(iso)}
      >
        <div className="cal-day-top">
          <span className="cal-day">{day}</span>
          {dayEvents.length > 0 && <span className="cal-count">{dayEvents.length}</span>}
        </div>
        {dayEvents.length > 0 && (
          <div className="cal-dots" aria-hidden>
            {dayEvents.slice(0, 4).map((ev, i) => (
              <span key={`${ev.date}-${ev.symbol || ""}-${i}`} className={dotClass(ev)} />
            ))}
            {dayEvents.length > 4 && <span className="cal-dots-more">+</span>}
          </div>
        )}
        <div className="cal-events">
          {dayEvents.length === 0 ? (
            <span className="cal-quiet" />
          ) : (
            <>
              {dayEvents.slice(0, 2).map((ev, i) => (
                <span
                  key={`${ev.date}-${ev.symbol || ""}-${ev.title}-${i}`}
                  className={chipClass(ev)}
                  title={`${ev.titleZh || ev.title}${ev.time ? ` · ${ev.time}` : ""}${ev.note ? `\n${ev.note}` : ""}`}
                >
                  {calendarEventShortLabel(ev)}
                </span>
              ))}
              {dayEvents.length > 2 && <span className="cal-more">+{dayEvents.length - 2}</span>}
            </>
          )}
        </div>
      </button>,
    );
  }

  return (
    <div className="cal-board-wrap">
      <div className="cal-summary">
        <div className="cal-stat">
          <b>{eventCount}</b>
          <span>區間內事件</span>
        </div>
        <div className="cal-stat">
          <b>{range.start.slice(5)}</b>
          <span>起算（今天）</span>
        </div>
        <div className="cal-stat">
          <b>{range.end.slice(5)}</b>
          <span>結束（約兩個月）</span>
        </div>
        <div className="cal-stat">
          <b>{portfolioCount}</b>
          <span>背包財報檔數</span>
        </div>
      </div>

      <div className="cal-legend">
        <span>
          <i className="leg high" /> 高關注
        </span>
        <span>
          <i className="leg medium" /> 中關注
        </span>
        <span>
          <i className="leg fed" /> 聯準會
        </span>
        <span>
          <i className="leg deriv" /> 衍生品
        </span>
        <span>
          <i className="leg earn" /> 背包財報
        </span>
        <span className="cal-legend-note">點日期格子 → 下方看完整說明與 ? 解讀</span>
      </div>

      <div className="cal-layout">
        <section className="cal-month">
          <div className="cal-month-head">
            <div className="cal-nav">
              <button type="button" className="cal-nav-btn" onClick={goPrevMonth} disabled={!canPrev} aria-label="上個月">
                ‹
              </button>
              <h3>{viewMonthLabel}</h3>
              <button type="button" className="cal-nav-btn" onClick={goNextMonth} disabled={!canNext} aria-label="下個月">
                ›
              </button>
            </div>
            <button type="button" className="cal-today-btn" onClick={goToday}>
              今天
            </button>
          </div>
          <div className="cal-weekdays">
            {WEEKDAYS.map((w) => (
              <span key={w}>{w}</span>
            ))}
          </div>
          <div className="cal-grid">{cells}</div>
        </section>

        <CalendarDayDetail date={selectedDate} events={selectedEvents} />
      </div>
    </div>
  );
}