"use client"

import { useState, useEffect, useContext } from "react"
import { useLocale } from "next-intl"
import { motion, useReducedMotion } from "framer-motion"
import { useInView } from "react-intersection-observer"
import { ContexteRevelationPanneau } from "@/lib/panel-reveal"

/**
 * « Objectifs visés », le tir à l'arc.
 *
 * A gauche, un arc et une cible en perspective. L'arc se bande, décoche, la
 * flèche vole et se plante dans la cible ; à chaque impact, une carte objectif
 * apparaît à droite. Les cinq flèches tirées, les cinq cartes sont là, temps
 * de lecture, puis tout s'efface et le cycle repart : le dispositif ne
 * s'arrête jamais tant que la section est à l'écran.
 * Survol = pause. Repli mobile : la scène au-dessus, les cartes en dessous.
 */

type Objectif = {
  valeur: string
  labelFr: string
  labelEn: string
  /** Couleur de la flèche ET du filet de sa carte : c'est ce qui apparie les deux. */
  couleur: string
  /** Angle du point d'impact sur la cible, en degrés, repère local. */
  angle: number
  /** Rayon du point d'impact. Volontairement quasi identique d'un objectif à
   *  l'autre : sur une cible, s'éloigner du centre signifie « moins bien visé ».
   *  Faire varier ce rayon reviendrait à classer les objectifs entre eux. */
  rayon: number
}

const OBJECTIFS: Objectif[] = [
  { valeur: "100 000", labelFr: "bénéficiaires directs visés", labelEn: "targeted direct beneficiaries", couleur: "#7f1d1d", angle: 142, rayon: 4.4 },
  { valeur: "2 500", labelFr: "jeunes formés aux métiers d'avenir", labelEn: "young people trained for future jobs", couleur: "#b91c1c", angle: 170, rayon: 3.6 },
  { valeur: "+15 %", labelFr: "de scolarisation dans les zones d'intervention", labelEn: "school enrolment in target areas", couleur: "#dc2626", angle: 198, rayon: 4.9 },
  { valeur: "−30 %", labelFr: "d'empreinte environnementale des communautés ciblées", labelEn: "environmental footprint of target communities", couleur: "#e2661a", angle: 226, rayon: 3.9 },
  { valeur: "ISO 26000", labelFr: "certification RSE visée", labelEn: "targeted CSR certification", couleur: "#e8a33d", angle: 254, rayon: 4.2 },
]

const N = OBJECTIFS.length

/* ── Géométrie de la scène ─────────────────────────────────────────────────
   La scène est un SVG autonome : les cartes n'y sont plus arrimées, donc
   aucun repère partagé à maintenir entre le SVG et le HTML.               */

const VB_W = 100
const VB_H = 76

const CX = 66 // centre de la cible
const CY = 36
const TILT = -20 // basculement de la cible, en degrés
const SQUASH = 0.58 // écrasement vertical qui donne la perspective

// Bandes pleines alternées : le gris clair porte l'anneau, la couleur creuse
// est celle du fond de section (blanc). À reprendre si le fond change.
const RINGS = [
  { r: 22, fill: "#e2e8f0" },
  { r: 17.4, fill: "#ffffff" },
  { r: 12.7, fill: "#e2e8f0" },
  { r: 8, fill: "#ffffff" },
]
const BULLSEYE = 3.4

const BOW_X = 10 // dos de l'arc
const BOW_TOP = 22
const BOW_BOTTOM = 50
const NOCK = { x: 3.5, y: (BOW_TOP + BOW_BOTTOM) / 2 } // encoche, corde bandée

/** Projette un point du repère local de la cible vers celui du viewBox.
 *  Reproduit à la main la transformation SVG du groupe (échelle, puis rotation,
 *  puis translation) pour que les flèches se plantent exactement sur l'anneau visé. */
function impact(o: Objectif) {
  const a = (o.angle * Math.PI) / 180
  const t = (TILT * Math.PI) / 180
  const x = o.rayon * Math.cos(a)
  const y = o.rayon * Math.sin(a) * SQUASH
  return {
    x: CX + x * Math.cos(t) - y * Math.sin(t),
    y: CY + x * Math.sin(t) + y * Math.cos(t),
  }
}

const IMPACTS = OBJECTIFS.map(impact)

/** Trajectoire : la flèche part de l'encoche, passe par un sommet légèrement
 *  relevé, et arrive sur l'impact. On en tire aussi les deux angles de la
 *  flèche, pour qu'elle pique vers le bas en fin de course. */
const TRAJETS = IMPACTS.map((p) => {
  const mx = (NOCK.x + p.x) / 2
  const my = (NOCK.y + p.y) / 2 - 6
  const deg = (dx: number, dy: number) => (Math.atan2(dy, dx) * 180) / Math.PI
  return {
    x: [NOCK.x, mx, p.x],
    y: [NOCK.y, my, p.y],
    rotate: [deg(mx - NOCK.x, my - NOCK.y), deg(p.x - mx, p.y - my), deg(p.x - mx, p.y - my)],
    fin: deg(p.x - mx, p.y - my),
  }
})

/* ── Cadence ───────────────────────────────────────────────────────────── */

const DRAW_MS = 460 // l'arc se bande
const FLIGHT_MS = 420 // la flèche vole
const RELOAD_MS = 420 // temps avant d'encocher la suivante
const HOLD_MS = 3000 // les cinq cartes en place, temps de lecture
const CLEAR_MS = 700 // effacement avant reprise

/** `actif` : à passer lorsque le composant vit dans un panneau d'onglets, pour
 *  que le cycle s'arrête quand le panneau est masqué. Hors onglets, laisser le
 *  défaut : c'est alors la seule visibilité à l'écran qui commande. */
export default function ObjectifsCible({ actif = true }: { actif?: boolean }) {
  const locale = useLocale()
  const isEn = locale === "en"
  const reduce = useReducedMotion()
  const dansPanneau = useContext(ContexteRevelationPanneau)
  const [ref, vueEcran] = useInView({ threshold: 0.2 })
  // Un panneau inactif est en display:none : l'observateur d'intersection ne s'y
  // déclenche pas, et ne se rattrape pas non plus à l'affichage. Dans ce cas
  // c'est donc l'onglet qui commande le cycle, jamais la visibilité mesurée.
  const inView = dansPanneau ? actif : vueEcran

  const [plantees, setPlantees] = useState(0) // flèches déjà plantées
  const [envol, setEnvol] = useState(false) // une flèche est en vol
  const [effacement, setEffacement] = useState(false)
  const [cycle, setCycle] = useState(0) // force le rejeu des animations à chaque tour
  const [pause, setPause] = useState(false)

  useEffect(() => {
    if (reduce) {
      setPlantees(N)
      return
    }
    if (!inView || pause) return
    let id: ReturnType<typeof setTimeout>
    if (effacement) {
      id = setTimeout(() => {
        setEffacement(false)
        setPlantees(0)
        setCycle((c) => c + 1)
      }, CLEAR_MS)
    } else if (envol) {
      id = setTimeout(() => {
        setEnvol(false)
        setPlantees((p) => p + 1)
      }, FLIGHT_MS)
    } else if (plantees < N) {
      // Bandage de l'arc, puis décochage. Le tout premier tir attend un peu
      // moins : la section vient d'entrer dans le champ, on ne fait pas patienter.
      id = setTimeout(() => setEnvol(true), plantees === 0 ? DRAW_MS : DRAW_MS + RELOAD_MS)
    } else {
      id = setTimeout(() => setEffacement(true), HOLD_MS)
    }
    return () => clearTimeout(id)
  }, [plantees, envol, effacement, inView, pause, reduce])

  const label = (o: Objectif) => (isEn ? o.labelEn : o.labelFr)
  const visible = (i: number) => i < plantees && !effacement
  // L'arc n'est bandé que lorsqu'il reste une flèche à tirer et qu'aucune n'est en vol
  const bande = !envol && !effacement && plantees < N

  return (
    <div
      ref={ref}
      className="flex flex-col items-center gap-8 lg:flex-row lg:gap-14"
      onMouseEnter={() => setPause(true)}
      onMouseLeave={() => setPause(false)}
    >
      {/* ── La scène : l'arc, la cible, les flèches ─────────────────────── */}
      <div className="w-full max-w-[520px] shrink-0 lg:max-w-none lg:flex-[0_0_52%]">
        <svg viewBox={`0 0 ${VB_W} ${VB_H}`} className="h-auto w-full" aria-hidden>
          {/* Cible */}
          <g transform={`translate(${CX} ${CY}) rotate(${TILT}) scale(1 ${SQUASH})`}>
            {RINGS.map((ring) => (
              <circle key={ring.r} cx="0" cy="0" r={ring.r} fill={ring.fill} stroke="rgba(0,0,0,0.05)" strokeWidth="0.22" />
            ))}
            <circle cx="0" cy="0" r={BULLSEYE} className="fill-primary" />
          </g>

          {/* Le tireur, réduit à son arc : deux branches et une corde.
              Pas de silhouette humaine, la scène reste géométrique. */}
          <g stroke="#4b5563" fill="none" strokeLinecap="round">
            <path d={`M ${BOW_X},${BOW_TOP} Q ${BOW_X + 8},${(BOW_TOP + BOW_BOTTOM) / 2} ${BOW_X},${BOW_BOTTOM}`} strokeWidth="0.9" />
            {/* La corde bascule d'un état à l'autre par simple rendu, sans
                transition : le décochage EST une rupture, l'animer l'amollirait.
                Elle reste bandée le temps du rechargement, ce qui donne le
                temps de voir l'arc tendu avant le départ. */}
            <polyline
              points={
                bande
                  ? `${BOW_X},${BOW_TOP} ${NOCK.x},${NOCK.y} ${BOW_X},${BOW_BOTTOM}`
                  : `${BOW_X},${BOW_TOP} ${BOW_X},${BOW_BOTTOM}`
              }
              strokeWidth="0.35"
            />
          </g>

          {/* Flèche encochée, prête à partir */}
          {bande && !reduce && (
            <g transform={`translate(${NOCK.x} ${NOCK.y})`}>
              <Fleche couleur={OBJECTIFS[plantees].couleur} />
            </g>
          )}

          {/* Flèche en vol */}
          {envol && !reduce && (
            <motion.g
              key={`vol-${plantees}-${cycle}`}
              style={{ transformBox: "fill-box", transformOrigin: "100% 50%" }}
              initial={{ x: TRAJETS[plantees].x[0], y: TRAJETS[plantees].y[0], rotate: TRAJETS[plantees].rotate[0] }}
              animate={{ x: TRAJETS[plantees].x, y: TRAJETS[plantees].y, rotate: TRAJETS[plantees].rotate }}
              transition={{ duration: FLIGHT_MS / 1000, ease: "linear", times: [0, 0.5, 1] }}
            >
              <Fleche couleur={OBJECTIFS[plantees].couleur} />
            </motion.g>
          )}

          {/* Flèches plantées, et leur onde d'impact */}
          {OBJECTIFS.map((o, i) =>
            visible(i) ? (
              <g key={`plantee-${i}-${cycle}`}>
                <motion.circle
                  cx={IMPACTS[i].x} cy={IMPACTS[i].y}
                  fill="none" stroke={o.couleur} strokeWidth="0.25"
                  initial={{ r: 0.5, opacity: 0.9 }}
                  animate={{ r: 4.2, opacity: 0 }}
                  transition={{ duration: reduce ? 0 : 0.65, ease: "easeOut" }}
                />
                <g
                  transform={`translate(${IMPACTS[i].x} ${IMPACTS[i].y}) rotate(${TRAJETS[i].fin})`}
                >
                  <Fleche couleur={o.couleur} plantee />
                </g>
              </g>
            ) : null
          )}
        </svg>
      </div>

      {/* ── Les cartes, qui s'ajoutent à chaque impact ──────────────────── */}
      {/* Les cinq cartes occupent toujours leur place : elles ne font que
          changer d'opacité, donc la hauteur du bloc ne bouge jamais et la
          page ne saute pas au fil des apparitions. */}
      <div className="w-full space-y-3.5 lg:flex-1">
        {OBJECTIFS.map((o, i) => (
          <motion.div
            key={o.valeur}
            // Une puce ronde a la place du filet vertical : c'est le signe des
            // listes du site, et il porte la couleur de la fleche qui a produit
            // la ligne.
            className="flex items-start gap-3 bg-white py-2 pr-2"
            initial={{ opacity: 0, x: 24 }}
            animate={visible(i) ? { opacity: 1, x: 0 } : { opacity: 0, x: 24 }}
            transition={{ duration: reduce ? 0 : 0.38, ease: [0.16, 1, 0.3, 1] }}
          >
            <span
              className="mt-[9px] h-2 w-2 flex-shrink-0 rounded-full"
              style={{ backgroundColor: o.couleur }}
              aria-hidden
            />
            <span className="min-w-0">
              <span className="block text-2xl font-bold leading-none tabular-nums tracking-tight text-gray-900 lg:text-3xl">
                {o.valeur}
              </span>
              <span className="mt-2 block text-[14px] leading-snug text-gray-500">{label(o)}</span>
            </span>
          </motion.div>
        ))}
      </div>
    </div>
  )
}

/* ── La flèche ─────────────────────────────────────────────────────────────
   Dessinée pointe à l'origine et fût vers la gauche, de sorte que la pointe
   soit à la fois le point de rotation et le point d'impact.               */

function Fleche({ couleur, plantee = false }: { couleur: string; plantee?: boolean }) {
  const queue = plantee ? -5.5 : -9
  return (
    <g stroke={couleur} strokeLinecap="round">
      <line x1={queue} y1="0" x2="0" y2="0" strokeWidth="0.42" />
      <polygon points="0,0 -2.1,-1 -2.1,1" fill={couleur} stroke="none" />
      <line x1={queue} y1="0" x2={queue - 1.8} y2="-1.3" strokeWidth="0.34" />
      <line x1={queue} y1="0" x2={queue - 1.8} y2="1.3" strokeWidth="0.34" />
    </g>
  )
}
