// ABOUTME: Compact calendar widget for the dashboard.
// ABOUTME: Shows current month with color-coded cycle phases and navigation.
"use client";

import { getCycleDay, getPhase } from "@/lib/cycle";
import type { CyclePhase } from "@/types";

interface MiniCalendarProps {
  lastPeriodDate: Date;
  cycleLength: number;
  year?: number;
  month?: number;
  onMonthChange?: (year: number, month: number) => void;
}

const PHASE_COLORS: Record<CyclePhase, string> = {
  MENSTRUAL: "bg-blue-100",
  FOLLICULAR: "bg-green-100",
  OVULATION: "bg-purple-100",
  EARLY_LUTEAL: "bg-yellow-100",
  LATE_LUTEAL: "bg-red-100",
};

const COMPACT_DAY_NAMES = ["S", "M", "T", "W", "T", "F", "S"];

const PHASE_LEGEND = [
  { name: "Menstrual", color: "bg-blue-100" },
  { name: "Follicular", color: "bg-green-100" },
  { name: "Ovulation", color: "bg-purple-100" },
  { name: "Early Luteal", color: "bg-yellow-100" },
  { name: "Late Luteal", color: "bg-red-100" },
];

function getDaysInMonth(year: number, month: number): number {
  return new Date(year, month + 1, 0).getDate();
}

function getFirstDayOfMonth(year: number, month: number): number {
  return new Date(year, month, 1).getDay();
}

export function MiniCalendar({
  lastPeriodDate,
  cycleLength,
  year,
  month,
  onMonthChange,
}: MiniCalendarProps) {
  const today = new Date();
  const displayYear = year ?? today.getFullYear();
  const displayMonth = month ?? today.getMonth();

  const daysInMonth = getDaysInMonth(displayYear, displayMonth);
  const firstDayOfWeek = getFirstDayOfMonth(displayYear, displayMonth);

  // Calculate current cycle day and phase for the header
  const currentCycleDay = getCycleDay(lastPeriodDate, cycleLength, today);
  const currentPhase = getPhase(currentCycleDay, cycleLength);

  const handlePreviousMonth = () => {
    if (displayMonth === 0) {
      onMonthChange?.(displayYear - 1, 11);
    } else {
      onMonthChange?.(displayYear, displayMonth - 1);
    }
  };

  const handleNextMonth = () => {
    if (displayMonth === 11) {
      onMonthChange?.(displayYear + 1, 0);
    } else {
      onMonthChange?.(displayYear, displayMonth + 1);
    }
  };

  const handleTodayClick = () => {
    onMonthChange?.(today.getFullYear(), today.getMonth());
  };

  // Build array of day cells
  const days: (Date | null)[] = [];

  // Add empty cells for days before the first day of the month
  for (let i = 0; i < firstDayOfWeek; i++) {
    days.push(null);
  }

  // Add the actual days of the month
  for (let day = 1; day <= daysInMonth; day++) {
    days.push(new Date(displayYear, displayMonth, day));
  }

  return (
    <div className="rounded-lg border p-4">
      {/* Cycle info header */}
      <h3 className="font-semibold mb-2">
        Day {currentCycleDay} · {currentPhase}
      </h3>

      {/* Navigation with month/year */}
      <div className="flex items-center justify-between mb-3">
        <button
          type="button"
          onClick={handlePreviousMonth}
          className="p-1 hover:bg-gray-100 rounded text-sm"
          aria-label="Previous month"
        >
          ←
        </button>
        <div className="flex items-center gap-2">
          <span className="text-sm font-medium">
            {new Date(displayYear, displayMonth).toLocaleDateString("en-US", {
              month: "long",
              year: "numeric",
            })}
          </span>
          <button
            type="button"
            onClick={handleTodayClick}
            className="px-2 py-0.5 text-xs border rounded hover:bg-gray-100"
          >
            Today
          </button>
        </div>
        <button
          type="button"
          onClick={handleNextMonth}
          className="p-1 hover:bg-gray-100 rounded text-sm"
          aria-label="Next month"
        >
          →
        </button>
      </div>

      {/* Compact day of week headers */}
      <div className="grid grid-cols-7 gap-0.5 mb-1">
        {COMPACT_DAY_NAMES.map((dayName, index) => (
          <div
            // biome-ignore lint/suspicious/noArrayIndexKey: Day names are fixed and index is stable
            key={`day-header-${index}`}
            className="text-center text-xs font-medium text-gray-500"
          >
            {dayName}
          </div>
        ))}
      </div>

      {/* Calendar grid */}
      <div className="grid grid-cols-7 gap-0.5">
        {days.map((date, index) => {
          if (!date) {
            // biome-ignore lint/suspicious/noArrayIndexKey: Empty cells are always at fixed positions at the start of the month
            return <div key={`empty-${index}`} className="p-1" />;
          }

          const cycleDay = getCycleDay(lastPeriodDate, cycleLength, date);
          const phase = getPhase(cycleDay, cycleLength);
          const isToday =
            date.getFullYear() === today.getFullYear() &&
            date.getMonth() === today.getMonth() &&
            date.getDate() === today.getDate();

          return (
            <button
              type="button"
              key={date.toISOString()}
              className={`p-1 text-xs rounded ${PHASE_COLORS[phase]} ${
                isToday ? "ring-2 ring-black font-bold" : ""
              }`}
            >
              {date.getDate()}
            </button>
          );
        })}
      </div>

      {/* Compact phase legend */}
      <div
        data-testid="phase-legend"
        className="mt-3 flex flex-wrap gap-2 justify-center"
      >
        {PHASE_LEGEND.map((phase) => (
          <div key={phase.name} className="flex items-center gap-0.5">
            <div className={`w-2 h-2 rounded ${phase.color}`} />
            <span className="text-xs text-gray-600">{phase.name}</span>
          </div>
        ))}
      </div>
    </div>
  );
}
