import {
  useEffect,
  useRef,
  useState,
  type CSSProperties,
  type ReactNode,
} from "react";
import { LAPS } from "./steerConfig";
import { polar } from "./physics";

// First-launch tutorial: a tiny 3-slide carousel shown once (after the player
// hits "Larguez les amarres") over the frozen sea. Skipping or finishing marks
// it seen so it never shows again. Illustrations reuse the game's real UI
// components (helm pads + tiller, crew-call buttons, HUD metrics) so what the
// player sees here is exactly what they'll drive.

// Slide 1 - the helm: the two steering cards with the wooden tiller nestled in
// their scoop, rebuilt from the live .ctrl markup (positioning overridden by
// .tt-helm).
function HelmArt() {
  return (
    <div className="tt-helm" aria-hidden="true">
      <div className="pad padl">
        <div className="padcard lofer">
          <div className="padbtn lofer">
            <div className="padeff lofer">Lofer</div>
          </div>
        </div>
      </div>
      <div className="tiller">
        <div className="tillerdial">
          <svg className="tillersvg" viewBox="0 0 48 64">
            <g transform="translate(24 32) rotate(-90) scale(0.078) translate(-100 -92)">
              <image href="/barre.svg" width="874" height="185" />
            </g>
          </svg>
        </div>
      </div>
      <div className="pad padr">
        <div className="padcard abattre">
          <div className="padbtn abattre">
            <div className="padeff abattre">Abattre</div>
          </div>
        </div>
      </div>
    </div>
  );
}

// Slide 2 - points of sail: a compact replica of the game's easy-mode "allure
// ring" (same angles, labels and dashed grey style as steerRender.allureRing).
// Wind blows from the top; 0deg is head-to-wind (no-go), 180deg is dead run.
const ALLURES: [string, number][] = [
  ["Près", 52],
  ["Bon plein", 69],
  ["Travers", 89],
  ["Largue", 115],
  ["Grand largue", 140],
];
const ALLURE_DIVS = [43, 60, 78, 100, 130, 150];

// Wedge half-angles, straight from physics.ts (NOGO / GYBE).
const NOGO = 43;
const GYBE = 30;

function AllureArt() {
  const cx = 140;
  const cy = 104;
  const R = 82;
  const rDiv = 30; // inner radius where sector dividers start
  const rLab = R + 9; // labels: their INNER edge sits on this circle (even spacing)
  const pt = (aDeg: number, r: number, s = 1) => {
    const a = (aDeg * Math.PI) / 180;
    return [cx + s * r * Math.sin(a), cy - r * Math.cos(a)] as const;
  };
  // Pie slice symmetric about the vertical axis: `edge` is the off-wind angle of
  // each side. Upwind (edge=NOGO) sweeps through the top; downwind
  // (edge=180-GYBE) sweeps through the bottom.
  const wedgeTop = (edge: number) => {
    const l = pt(edge, R, -1);
    const r = pt(edge, R, 1);
    return `M ${cx} ${cy} L ${l[0]} ${l[1]} A ${R} ${R} 0 0 1 ${r[0]} ${r[1]} Z`;
  };
  const wedgeBottom = (edge: number) => {
    const l = pt(edge, R, -1);
    const r = pt(edge, R, 1);
    return `M ${cx} ${cy} L ${r[0]} ${r[1]} A ${R} ${R} 0 0 1 ${l[0]} ${l[1]} Z`;
  };
  // Relative-speed polar: the boat's actual target speed at each allure, straight
  // from physics.polar(). Radius at angle a = polar(a) * rSpeed, mirrored on both
  // tacks -> a closed blob that's fat where the boat is fast (reach), pinched to
  // nothing in the no-go, and only medium dead downwind.
  const rSpeed = 66; // max speed radius, kept inside the ring (R = 82)
  const speedD = (() => {
    const step = 4;
    const seg: string[] = [];
    for (let a = 0; a <= 180; a += step) {
      const [x, y] = pt(a, polar(a) * rSpeed, 1);
      seg.push(`${x.toFixed(1)} ${y.toFixed(1)}`);
    }
    for (let a = 180; a >= 0; a -= step) {
      const [x, y] = pt(a, polar(a) * rSpeed, -1);
      seg.push(`${x.toFixed(1)} ${y.toFixed(1)}`);
    }
    return "M " + seg.join(" L ") + " Z";
  })();
  return (
    <svg className="tt-allure" viewBox="0 0 280 216" aria-hidden="true">
      <defs>
        {/* Same radial fade as the game's drawWedge: melts out toward the rim. */}
        <radialGradient
          id="tt-wedge"
          gradientUnits="userSpaceOnUse"
          cx={cx}
          cy={cy}
          r={R}
        >
          <stop offset="0" stopColor="rgba(221,138,38,0)" />
          <stop offset="0.4" stopColor="rgba(221,138,38,0.05)" />
          <stop offset="1" stopColor="rgba(221,138,38,0.34)" />
        </radialGradient>
      </defs>
      {/* relative-speed polar (under the zone wedges so orange never muddies it):
          the green area shows how fast the boat sails at each allure */}
      <path className="al-speed" d={speedD} />
      {/* upwind no-go zone (dashed edges) */}
      <path className="al-wedge al-nogo" d={wedgeTop(NOGO)} />
      {/* downwind gybe / vent-arrière zone (soft, no dashed edges) */}
      <path className="al-wedge" d={wedgeBottom(180 - GYBE)} />
      {/* dashed ring */}
      <circle className="al-ring" cx={cx} cy={cy} r={R} />
      {/* radial sector dividers, both tacks */}
      {ALLURE_DIVS.flatMap((d) =>
        [1, -1].map((s) => {
          const a = pt(d, rDiv, s);
          const b = pt(d, R, s);
          return (
            <line
              key={`${d}:${s}`}
              className="al-div"
              x1={a[0]}
              y1={a[1]}
              x2={b[0]}
              y2={b[1]}
            />
          );
        })
      )}
      {/* wind blowing down INSIDE the ring, toward the boat */}
      <line className="al-wind" x1={cx} y1={cy - R + 16} x2={cx} y2={cy - 44} />
      <path className="al-windfill" d={`M ${cx} ${cy - 36} l -6 -10 l 12 0 z`} />
      {/* boat at the centre: the game's cream hull + red sails, pointing up */}
      <g transform={`translate(${cx} ${cy}) scale(0.62)`}>
        <path
          className="al-hull"
          d="M0 -25.3 Q11 -4.6 8 18.4 Q0 25.3 -8 18.4 Q-11 -4.6 0 -25.3 Z"
        />
        <path className="al-sail" d="M0 -22 Q9 -13 3 -5 Q0 -7 0 -22 Z" />
        <path className="al-sail" d="M0 -2 Q12 9 4 20 Q0 18 0 -2 Z" />
        <circle className="al-mast" cx="0" cy="-2.3" r="1.8" />
      </g>
      {/* labels: top/bottom centred, sides aligned by their inner edge so every
          allure reads at the same distance from the ring. */}
      <text className="al-lab" x={cx} y={cy - R - 9} textAnchor="middle">
        Vent debout
      </text>
      <text className="al-lab" x={cx} y={cy + R + 16} textAnchor="middle">
        Vent arrière
      </text>
      {ALLURES.flatMap(([txt, a]) =>
        [1, -1].map((s) => {
          const p = pt(a, rLab, s);
          return (
            <text
              key={`${txt}:${s}`}
              className="al-lab"
              x={p[0]}
              y={p[1]}
              textAnchor={s === 1 ? "start" : "end"}
            >
              {txt}
            </text>
          );
        })
      )}
    </svg>
  );
}

// Slide 3 - the crew calls: the two "Paré à ..." buttons, straight from the live
// .annbtn markup. They "self-click" in turn (see .tt-calls animation) to mime the
// announce ritual; the danger of skipping it lives in the slide text.
function CallsArt() {
  return (
    <div className="tt-calls" aria-hidden="true">
      <div className="annbtn" style={{ "--prep": 0.62 } as CSSProperties}>
        <span className="annlab">
          <span className="anneye">Paré à</span>
          <b className="annverb">Virer</b>
        </span>
      </div>
      <div className="annbtn">
        <span className="annlab">
          <span className="anneye">Paré à</span>
          <b className="annverb">Empanner</b>
        </span>
      </div>
    </div>
  );
}

// Slide 4 - the bearing: a static replica of the game's off-screen mark pointer
// (steerRender.drawOffscreenArrow) - a red arrow aimed at the next buoy, its
// distance readout, and the small curved glyph telling you which side to round.
function BearingArt() {
  return (
    <svg className="tt-bearing" viewBox="0 0 280 216" aria-hidden="true">
      {/* faint bearing guide from the boat out to the buoy */}
      <line className="ga-guide" x1="84" y1="150" x2="206" y2="66" />
      {/* your boat, lower-left, pointing up toward the objective */}
      <g transform="translate(70 168) rotate(50) scale(0.58)">
        <path
          className="al-hull"
          d="M0 -25.3 Q11 -4.6 8 18.4 Q0 25.3 -8 18.4 Q-11 -4.6 0 -25.3 Z"
        />
        <path className="al-sail" d="M0 -22 Q9 -13 3 -5 Q0 -7 0 -22 Z" />
        <path className="al-sail" d="M0 -2 Q12 9 4 20 Q0 18 0 -2 Z" />
        <circle className="al-mast" cx="0" cy="-2.3" r="1.8" />
      </g>
      {/* the red pointer: readout (rounding glyph + distance) then the arrow, all
          on the exact bearing to the buoy, lifted with a soft drop-shadow */}
      <g className="ga-pointer">
        <g transform="translate(104 116)">
          <path
            className="ga-glyph"
            d="M0 -5.6 A 5.6 5.6 0 1 1 -5.4 -1.5"
            fill="none"
          />
          <path className="ga-glyphhead" d="M-5.4 -1.5 l -3.1 -0.9 l 1.7 2.9 z" />
        </g>
        <text className="ga-dist" x="116" y="116">
          120&#8202;m
        </text>
        <g transform="translate(170 92) rotate(50)">
          <path className="ga-arrow" d="M0 -12 L6.4 4 L-6.4 4 Z" />
        </g>
      </g>
      {/* the next buoy the arrow points at */}
      <g transform="translate(214 58) scale(1.5)">
        <path
          className="ga-buoy"
          d="M-6 5 Q-8 -3 0 -8 Q8 -3 6 5 Q0 9 -6 5 Z"
        />
        <path className="ga-band" d="M-5.5 0.5 Q0 2.5 5.5 0.5" fill="none" />
        <line className="ga-mast" x1="0" y1="-8" x2="0" y2="-21" />
        <path className="ga-pennant" d="M-1.6 -21 Q4 -15 3 -9 Q-0.5 -14 -0.4 -21 Z" />
      </g>
    </svg>
  );
}

// Slide 5 - the objective: the HUD metric trio the player chases (laps, buoys,
// time), reusing the live .metric / .eyebrow / .speed styles.
const GOAL_BUOYS = 2; // buoys per lap on the demo windward-leeward
const GOAL_SECS_PER_BUOY = 4; // demo pace: a buoy is rounded every few seconds
const GOAL_LOOP = LAPS * GOAL_BUOYS * GOAL_SECS_PER_BUOY; // full "race" before it replays

function GoalArt() {
  // A tiny looping "race": the clock ticks up every second while the buoy and
  // lap counters climb like a real run (buoy 1/2 -> 2/2, then next lap), then it
  // resets so the counters are always visibly moving.
  const [t, setT] = useState(0);
  useEffect(() => {
    const id = window.setInterval(() => setT((s) => (s + 1) % GOAL_LOOP), 1000);
    return () => window.clearInterval(id);
  }, []);
  const buoyIndex = Math.floor(t / GOAL_SECS_PER_BUOY); // 0..(LAPS*GOAL_BUOYS-1)
  const lap = Math.floor(buoyIndex / GOAL_BUOYS) + 1;
  const buoy = (buoyIndex % GOAL_BUOYS) + 1;
  const time = `${Math.floor(t / 60)}:${(t % 60).toString().padStart(2, "0")}`;

  // Bounce the Tour / Bouées counters on each increment, exactly like the live
  // HUD: retrigger the game's `pop` animation (remove class -> reflow -> add).
  // Seed the "previous" refs with the initial values so the counters DON'T pop on
  // arrival - only on the first real change and onward.
  const lapRef = useRef<HTMLDivElement>(null);
  const buoyRef = useRef<HTMLDivElement>(null);
  const prevLap = useRef(lap);
  const prevBuoy = useRef(buoy);
  useEffect(() => {
    if (prevLap.current === lap) return;
    prevLap.current = lap;
    bounce(lapRef.current);
  }, [lap]);
  useEffect(() => {
    if (prevBuoy.current === buoy) return;
    prevBuoy.current = buoy;
    bounce(buoyRef.current);
  }, [buoy]);

  return (
    <div className="tt-goal" aria-hidden="true">
      <div className="metric">
        <div className="eyebrow">Tour</div>
        <div className="speed" ref={lapRef}>
          {lap}/{LAPS}
        </div>
      </div>
      <div className="metric">
        <div className="eyebrow">Bouées</div>
        <div className="speed" ref={buoyRef}>
          {buoy}/{GOAL_BUOYS}
        </div>
      </div>
      <div className="metric">
        <div className="eyebrow">Temps</div>
        <div className="speed">{time}</div>
      </div>
    </div>
  );
}

// Retrigger the `pop` bounce on a counter (mirrors the game's reflow trick).
function bounce(el: HTMLElement | null) {
  if (!el) return;
  el.classList.remove("pop");
  void el.offsetWidth;
  el.classList.add("pop");
}

interface Slide {
  key: string;
  title: string;
  body: ReactNode;
  art: ReactNode;
}

const SLIDES: Slide[] = [
  {
    key: "barre",
    title: "La barre",
    body: (
      <>
        Maintiens <b>Lofer</b> (vers le vent) ou <b>Abattre</b> (loin du vent)
        pour faire tourner le bateau. Les <b>écoutes</b> (les cordages qui
        règlent les voiles) s'ajustent seules, avec un{" "}
        <b>léger temps de retard</b> - comme un vrai équipage.
      </>
    ),
    art: <HelmArt />,
  },
  {
    key: "allures",
    title: "Les allures",
    body: (
      <>
        Ton <b>allure</b>, c'est ton angle au vent - et c'est lui qui commande
        ta <b>vitesse</b> (la <b>zone verte</b>) : le bateau file au <b>largue</b>,
        cale <b>face au vent</b> (<b>zone interdite</b>) où il faut{" "}
        <b>tirer des bords</b> en zigzag pour remonter.
      </>
    ),
    art: <AllureArt />,
  },
  {
    key: "manoeuvres",
    title: "Les manœuvres",
    body: (
      <>
        Avant de traverser le lit du vent, préviens l'équipage :{" "}
        <b>Paré à virer</b> (près du vent) ou <b>Paré à empanner</b> (vent
        arrière). Sans annonce, la voile <b>claque violemment</b> d'un bord à
        l'autre - <b>manœuvre sauvage</b> qui te fait <b>perdre ta vitesse</b>.
      </>
    ),
    art: <CallsArt />,
  },
  {
    key: "cap",
    title: "Le cap",
    body: (
      <>
        Une <b>flèche rouge</b> pointe toujours vers ta <b>prochaine bouée</b> et
        t'indique la <b>distance</b> qui reste. Le petit <b>arc courbe</b> montre
        de quel <b>côté la contourner</b>.
      </>
    ),
    art: <BearingArt />,
  },
  {
    key: "but",
    title: "Le but",
    body: (
      <>
        Boucle le parcours <b>au plus vite</b> en passant chaque bouée{" "}
        <b>du bon côté</b>.
      </>
    ),
    art: <GoalArt />,
  },
];

export default function Tutorial({ onClose }: { onClose: () => void }) {
  const [i, setI] = useState(0);
  const last = i === SLIDES.length - 1;
  const slide = SLIDES[i];
  return (
    <div className="tuto">
      <div className="tutocard" key={slide.key}>
        <div className="tutoart">{slide.art}</div>
        <div className="tutotitle">{slide.title}</div>
        <div className="tutobody">{slide.body}</div>
        <div className="tutodots" aria-hidden="true">
          {SLIDES.map((s, n) => (
            <span key={s.key} className={"tutodot" + (n === i ? " on" : "")} />
          ))}
        </div>
        <div className="tutonav">
          <button type="button" className="tutoskip" onClick={onClose}>
            Passer
          </button>
          <button
            type="button"
            className="tutonext"
            onClick={() => (last ? onClose() : setI(i + 1))}
          >
            {last ? "C'est parti !" : "Suivant"}
          </button>
        </div>
      </div>
    </div>
  );
}
