"use client";

import { useMemo } from "react";
import type { ForgejoHeatmapDay } from "@/lib/api-forgejo";

interface ForgejoHeatmapProps {
  days: ForgejoHeatmapDay[];
  maxCount: number;
  isLoading?: boolean;
}

// Layout constants — match Forgejo's contribution graph
const CELL = 10;
const GAP = 3;
const STRIDE = CELL + GAP; // 13px per cell
const WEEKS = 53;
const LEFT = 28; // width reserved for Mon/Wed/Fri labels
const TOP = 18;  // height reserved for month labels

const MONTHS = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];

// Forgejo dark-mode green palette (levels 0–4)
const LEVEL_FILL = [
  "var(--surface-strong)",     // 0 — no activity
  "rgba(52,211,153,0.22)",     // 1
  "rgba(52,211,153,0.46)",     // 2
  "rgba(52,211,153,0.70)",     // 3
  "var(--success)",            // 4
];

function toLevel(count: number): number {
  if (count === 0) return 0;
  if (count <= 2) return 1;
  if (count <= 5) return 2;
  if (count <= 9) return 3;
  return 4;
}

function isoDate(d: Date): string {
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, "0");
  const day = String(d.getDate()).padStart(2, "0");
  return `${y}-${m}-${day}`;
}

export function ForgejoHeatmap({
  days,
  maxCount: _maxCount,
  isLoading = false,
}: ForgejoHeatmapProps) {
  const { weeks, monthLabels } = useMemo(() => {
    const data = new Map<string, number>(days.map((d) => [d.date, d.count]));

    // Start on the Sunday 52 weeks before the current week's Sunday,
    // so the last column always contains today and future cells are clipped.
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const start = new Date(today);
    start.setDate(start.getDate() - start.getDay());       // rewind to this week's Sunday
    start.setDate(start.getDate() - (WEEKS - 1) * 7);     // go back 52 more weeks

    type Cell = { date: string; count: number; future: boolean };
    const builtWeeks: Cell[][] = [];
    const monthLabelList: { weekIdx: number; label: string }[] = [];
    let lastMonth = -1;
    const cur = new Date(start);

    for (let w = 0; w < WEEKS; w++) {
      const week: Cell[] = [];
      for (let d = 0; d < 7; d++) {
        const dateStr = isoDate(cur);
        const month = cur.getMonth();
        if (d === 0 && month !== lastMonth) {
          monthLabelList.push({ weekIdx: w, label: MONTHS[month] });
          lastMonth = month;
        }
        week.push({ date: dateStr, count: data.get(dateStr) ?? 0, future: cur > today });
        cur.setDate(cur.getDate() + 1);
      }
      builtWeeks.push(week);
    }

    return { weeks: builtWeeks, monthLabels: monthLabelList };
  }, [days]);

  const svgW = LEFT + WEEKS * STRIDE;
  const svgH = TOP + 7 * STRIDE - GAP;

  if (isLoading) {
    return (
      <div
        className="animate-pulse rounded"
        style={{ width: svgW, height: svgH, background: "var(--surface-strong)" }}
      />
    );
  }

  return (
    <div>
      <div style={{ overflowX: "auto" }} className="flex justify-center">
        <svg
          width={svgW}
          height={svgH}
          aria-label="Issue activity heatmap"
          style={{ display: "block" }}
        >
          {/* Month labels */}
          {monthLabels.map(({ weekIdx, label }) => (
            <text
              key={`m-${weekIdx}`}
              x={LEFT + weekIdx * STRIDE}
              y={11}
              fontSize={10}
              fill="currentColor"
              className="text-muted"
            >
              {label}
            </text>
          ))}

          {/* Day-of-week labels: Mon=row1, Wed=row3, Fri=row5
              y = cell top + CELL - 2 puts the baseline near the bottom of the
              10px cell, which reads as vertically centred for a 10px font. */}
          {(["Mon", "Wed", "Fri"] as const).map((label, i) => (
            <text
              key={label}
              x={0}
              y={TOP + (i * 2 + 1) * STRIDE + CELL - 2}
              fontSize={10}
              fill="currentColor"
              className="text-muted"
            >
              {label}
            </text>
          ))}

          {/* Cells */}
          {weeks.map((week, wi) =>
            week.map((cell, di) =>
              cell.future ? null : (
                <rect
                  key={cell.date}
                  x={LEFT + wi * STRIDE}
                  y={TOP + di * STRIDE}
                  width={CELL}
                  height={CELL}
                  rx={2}
                  fill={LEVEL_FILL[toLevel(cell.count)]}
                >
                  <title>
                    {cell.date}
                    {cell.count > 0
                      ? `: ${cell.count} event${cell.count !== 1 ? "s" : ""}`
                      : ": no activity"}
                  </title>
                </rect>
              ),
            ),
          )}
        </svg>
      </div>

      {/* Legend */}
      <div className="mt-2 flex items-center justify-center gap-1.5 text-xs text-muted">
        <span>Less</span>
        {LEVEL_FILL.map((fill, i) => (
          <div
            key={i}
            style={{ width: CELL, height: CELL, borderRadius: 2, background: fill, flexShrink: 0 }}
          />
        ))}
        <span>More</span>
      </div>
      <p className="mt-1.5 text-center text-[10px] text-muted opacity-70">
        {days.reduce((sum, d) => sum + d.count, 0).toLocaleString()} contributions across all tracked repositories in the last 12 months.
      </p>
    </div>
  );
}
