/**
 * =============================================================================
 * QWHPI — Quebec Weekly Housing Price Index
 * Author  : Simon-Pierre Boucher
 * Contact : contact@spboucher.ai
 * File    : web/components/HeroChart.tsx
 * Purpose : Full-width hero area chart with draw-in animation, CI band and
 *           pulsing end point — geometry rebuilt to the measured width.
 * =============================================================================
 */
"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import type { Observation } from "../lib/api";

export default function HeroChart({ observations }: { observations: Observation[] }) {
  const wrapRef = useRef<HTMLDivElement>(null);
  const [width, setWidth] = useState(1120);

  useEffect(() => {
    const el = wrapRef.current;
    if (!el) return;
    const ro = new ResizeObserver((entries) => {
      const w = entries[0]?.contentRect.width;
      if (w) setWidth(Math.max(280, Math.round(w)));
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  const small = width < 560;
  const W = width;
  const H = small ? 190 : 240;
  const PAD = { l: small ? 6 : 30, r: small ? 64 : 96, t: 24, b: 22 };

  const geom = useMemo(() => {
    const obs = observations.filter((o) => !o.is_partial_month);
    if (obs.length < 2) return null;
    const vals = obs.map((o) => o.index_smoothed);
    const los = obs.map((o) => o.lower_95);
    const his = obs.map((o) => o.upper_95);
    const min = Math.min(...los);
    const max = Math.max(...his);
    const x = (i: number) =>
      PAD.l + (i / (obs.length - 1)) * (W - PAD.l - PAD.r);
    const y = (v: number) =>
      H - PAD.b - ((v - min) / (max - min || 1)) * (H - PAD.t - PAD.b);
    const pts = vals.map((v, i) => `${x(i).toFixed(1)},${y(v).toFixed(1)}`);
    const line = "M" + pts.join(" L");
    const area = line + ` L${x(obs.length - 1)},${H - PAD.b} L${x(0)},${H - PAD.b} Z`;
    const upper = his.map((v, i) => `${x(i).toFixed(1)},${y(v).toFixed(1)}`);
    const lower = los
      .map((v, i) => `${x(i).toFixed(1)},${y(v).toFixed(1)}`)
      .reverse();
    const band = "M" + upper.join(" L") + " L" + lower.join(" L") + " Z";
    const lastObs = obs[obs.length - 1];
    const yearStep = small ? 2 : 1; // fewer year labels on narrow screens
    return {
      line, area, band,
      lastX: x(obs.length - 1), lastY: y(vals[vals.length - 1]),
      last: lastObs,
      years: obs
        .map((o, i) => ({ o, i }))
        .filter(({ o }) => o.period.endsWith("-01")
          && Number(o.period.slice(0, 4)) % yearStep === (small ? 0 : 0))
        .map(({ o, i }) => ({ label: o.period.slice(0, 4), x: x(i) })),
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [observations, W, H, PAD.l, PAD.r]);

  if (!geom) return <div ref={wrapRef} />;

  return (
    <div ref={wrapRef} className="hero-chart card"
         aria-label="Quebec index history chart" role="img">
      <svg viewBox={`0 0 ${W} ${H}`}
           style={{ width: "100%", height: "auto", display: "block" }}>
        <defs>
          <linearGradient id="heroFill" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="var(--series-1)" stopOpacity="0.28" />
            <stop offset="100%" stopColor="var(--series-1)" stopOpacity="0.02" />
          </linearGradient>
        </defs>
        <path d={geom.band} fill="var(--band)" className="hero-band" />
        <path d={geom.area} fill="url(#heroFill)" className="hero-area" />
        <path d={geom.line} fill="none" stroke="var(--series-1)"
              strokeWidth={small ? 2.2 : 2.6} strokeLinejoin="round"
              strokeLinecap="round" className="hero-line" pathLength={1} />
        {geom.years.map((yr) => (
          <g key={yr.label}>
            <line x1={yr.x} x2={yr.x} y1={H - PAD.b} y2={H - PAD.b + 4}
                  stroke="var(--border-strong)" />
            <text x={yr.x} y={H - 6} fontSize={small ? 11 : 10.5}
                  textAnchor="middle" fill="var(--text-muted)">{yr.label}</text>
          </g>
        ))}
        <circle cx={geom.lastX} cy={geom.lastY} r="4.5"
                fill="var(--series-1)" className="hero-dot" />
        <circle cx={geom.lastX} cy={geom.lastY} r="9"
                fill="var(--series-1)" opacity="0.25" className="hero-pulse" />
        <text x={geom.lastX + 12} y={geom.lastY - 5} fontSize={small ? 13 : 15}
              fontWeight="700" fill="var(--text-primary)" className="hero-dot">
          {geom.last.index_smoothed.toFixed(1)}
        </text>
        <text x={geom.lastX + 12} y={geom.lastY + 10} fontSize={small ? 9.5 : 10}
              fill="var(--text-muted)" className="hero-dot">
          {geom.last.period}
        </text>
      </svg>
    </div>
  );
}
