// components.jsx — reusable building blocks for Goudmeijer redesign

const { useState, useMemo, useEffect, useRef } = React;

// ─────────── Scroll reveal hook ───────────
// Adds `is-in` to the element (and any descendants that share the .reveal class)
// once it crosses ~12% into view.
function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll(".reveal, .stagger, .reveal-root");
    if (!("IntersectionObserver" in window)) {
      els.forEach((e) => e.classList.add("is-in"));
      return;
    }
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((en) => {
          if (en.isIntersecting) {
            en.target.classList.add("is-in");
            io.unobserve(en.target);
          }
        });
      },
      { threshold: 0.12, rootMargin: "0px 0px -8% 0px" }
    );
    els.forEach((e) => io.observe(e));
    return () => io.disconnect();
  });
}

// ─────────── CountUp ───────────
// Animates a number from 0 → value over `dur` ms when it scrolls into view.
function CountUp({ value, dur = 1400, prefix = "", suffix = "", decimals = 2, locale = "nl-NL" }) {
  const [n, setN] = useState(0);
  const ref = useRef(null);
  const started = useRef(false);

  useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((en) => {
          if (en.isIntersecting && !started.current) {
            started.current = true;
            const start = performance.now();
            const tick = (t) => {
              const p = Math.min(1, (t - start) / dur);
              // ease out cubic
              const eased = 1 - Math.pow(1 - p, 3);
              setN(value * eased);
              if (p < 1) requestAnimationFrame(tick);
              else setN(value);
            };
            requestAnimationFrame(tick);
            io.disconnect();
          }
        });
      },
      { threshold: 0.4 }
    );
    io.observe(ref.current);
    return () => io.disconnect();
  }, [value, dur]);

  const formatted = new Intl.NumberFormat(locale, {
    minimumFractionDigits: decimals,
    maximumFractionDigits: decimals,
  }).format(n);
  return (
    <span ref={ref} className="num-anim">
      {prefix}
      {formatted}
      {suffix}
    </span>
  );
}

// ─────────── Gold price chart ───────────
function PriceChart({ data, height = 240, accent = "#A07A36", ink = "#1B2A24" }) {
  const ref = useRef(null);
  const [w, setW] = useState(680);
  useEffect(() => {
    if (!ref.current) return;
    const ro = new ResizeObserver(([e]) => setW(e.contentRect.width));
    ro.observe(ref.current);
    return () => ro.disconnect();
  }, []);

  const min = Math.min(...data) - 0.5;
  const max = Math.max(...data) + 0.5;
  const xStep = w / (data.length - 1);
  const yScale = (v) => height - 24 - ((v - min) / (max - min)) * (height - 48);

  const pts = data.map((v, i) => [i * xStep, yScale(v)]);
  const path = pts.map((p, i) => (i === 0 ? `M${p[0]},${p[1]}` : `L${p[0]},${p[1]}`)).join(" ");
  const area = `${path} L${(data.length - 1) * xStep},${height} L0,${height} Z`;

  // Approximate path length for stroke-dasharray drawing animation
  const len = Math.round(w * 1.4);

  return (
    <div ref={ref} className="reveal chart-wrap" style={{ width: "100%" }}>
      <svg className="chart" width={w} height={height} viewBox={`0 0 ${w} ${height}`}>
        <defs>
          <linearGradient id="grad" x1="0" x2="0" y1="0" y2="1">
            <stop offset="0%" stopColor={accent} stopOpacity="0.18" />
            <stop offset="100%" stopColor={accent} stopOpacity="0" />
          </linearGradient>
        </defs>
        {[0.25, 0.5, 0.75].map((g, i) => (
          <line key={i} x1="0" x2={w} y1={height * g} y2={height * g} stroke={ink} strokeOpacity="0.07" strokeDasharray="2 4" />
        ))}
        <path className="chart-area" d={area} fill="url(#grad)" />
        <path className="chart-line" style={{ ["--len"]: len }} d={path} fill="none" stroke={accent} strokeWidth="1.5" strokeLinecap="round" />
        {pts.map((p, i) => (
          <g key={i} className={`chart-dot ${i === data.length - 1 ? "last" : ""}`}>
            <circle cx={p[0]} cy={p[1]} r={i === data.length - 1 ? 4 : 2.2} fill={i === data.length - 1 ? accent : ink} />
            {i === data.length - 1 && (
              <circle cx={p[0]} cy={p[1]} r="9" fill="none" stroke={accent} strokeOpacity=".35">
                <animate attributeName="r" values="9;14;9" dur="2.4s" repeatCount="indefinite" />
                <animate attributeName="stroke-opacity" values=".5;0;.5" dur="2.4s" repeatCount="indefinite" />
              </circle>
            )}
          </g>
        ))}
        <text x={pts[pts.length - 1][0] - 8} y={pts[pts.length - 1][1] - 14} textAnchor="end"
          fontFamily="Geist Mono, monospace" fontSize="11" fill={ink} letterSpacing="0.04em">
          €{data[data.length - 1].toFixed(2)}
        </text>
        <text x="4" y="14" fontFamily="Geist Mono, monospace" fontSize="10" fill={ink} fillOpacity=".5" letterSpacing=".08em">HOOG €{Math.max(...data).toFixed(2)}</text>
        <text x="4" y={height - 6} fontFamily="Geist Mono, monospace" fontSize="10" fill={ink} fillOpacity=".5" letterSpacing=".08em">LAAG €{Math.min(...data).toFixed(2)}</text>
      </svg>
    </div>
  );
}

// ─────────── Gold calculator ───────────
const KARATS = [
  { k: "8kt", purity: 0.333, label: "8 kt" },
  { k: "14kt", purity: 0.585, label: "14 kt" },
  { k: "18kt", purity: 0.750, label: "18 kt" },
  { k: "22kt", purity: 0.916, label: "22 kt" },
  { k: "24kt", purity: 0.999, label: "24 kt" },
];

const MATERIALS = [
  { id: "gold", label: "Goud", pricePerGram: 125.66 },
  { id: "silver", label: "Zilver", pricePerGram: 1.18 },
];

function Calculator({ variant = "full" }) {
  const [material, setMaterial] = useState("gold");
  const [karat, setKarat] = useState("14kt");
  const [grams, setGrams] = useState(25);

  const mat = MATERIALS.find((m) => m.id === material);
  const purity = material === "gold" ? KARATS.find((k) => k.k === karat).purity : 0.925;
  const spot = mat.pricePerGram;
  const estimate = grams * spot * purity;
  const offerLow = estimate * 0.74;
  const offerHigh = estimate * 0.88;

  const fmt = (n) =>
    new Intl.NumberFormat("nl-NL", { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(n);

  return (
    <div className={variant === "mini" ? "calc-mini" : "calc-shell"}>
      {variant === "full" && (
        <div>
          <span className="eyebrow">Goudcalculator</span>
          <h2 style={{ marginTop: 18 }}>Bereken in <em className="italic">één minuut</em> wat uw goud waard is.</h2>
          <p className="blurb">
            Een eerste indicatie op basis van de actuele goudprijs en gemiddelde inkooptarieven.
            Voor een precieze waardebepaling rekenen we mee met stempel, vorm, edelstenen en zeldzaamheid.
          </p>
          <a className="calc-cta">Plan een fysieke taxatie <span style={{ fontStyle: "italic", fontFamily: "var(--serif)", fontSize: 18 }}>→</span></a>
        </div>
      )}

      <div className="calc-form">
        {variant === "mini" && (
          <span className="calc-lbl" style={{ marginBottom: 4 }}>Snelle waardebepaling</span>
        )}

        <div className="calc-row">
          <span className="calc-lbl">Materiaal</span>
          <div className="seg">
            {MATERIALS.map((m) => (
              <button key={m.id} className={material === m.id ? "on" : ""} onClick={() => setMaterial(m.id)}>{m.label}</button>
            ))}
          </div>
        </div>

        {material === "gold" && (
          <div className="calc-row">
            <span className="calc-lbl">Karaat</span>
            <div className="seg">
              {KARATS.map((k) => (
                <button key={k.k} className={karat === k.k ? "on" : ""} onClick={() => setKarat(k.k)}>{k.label}</button>
              ))}
            </div>
          </div>
        )}

        <div className="calc-row">
          <span className="calc-lbl">Gewicht</span>
          <div className="gram-input">
            <input
              type="number"
              min="0"
              max="2000"
              step="0.1"
              value={grams}
              onChange={(e) => setGrams(Math.max(0, parseFloat(e.target.value) || 0))}
            />
            <span className="suffix">gram</span>
          </div>
          <input
            className="calc-slider"
            type="range"
            min="1"
            max="500"
            step="1"
            value={Math.min(grams, 500)}
            onChange={(e) => setGrams(parseFloat(e.target.value))}
          />
          <div style={{ display: "flex", justifyContent: "space-between", fontFamily: "var(--mono)", fontSize: 10, letterSpacing: ".1em", color: "rgba(250,246,233,.45)" }}>
            <span>1 g</span><span>500 g</span>
          </div>
        </div>

        <div className="calc-result">
          <div>
            <span className="lbl">Geschat marktwaarde</span>
            <div className="num" style={{ marginTop: 8 }}>
              <span className="e">€</span>{fmt(estimate)}
            </div>
          </div>
          <div style={{ textAlign: "right" }}>
            <span className="lbl">Inkoop-indicatie</span>
            <div style={{ fontFamily: "var(--serif)", fontSize: 22, marginTop: 10, color: "var(--gold)" }}>
              €{fmt(offerLow)} – €{fmt(offerHigh)}
            </div>
          </div>
        </div>
        <p className="calc-note">
          Indicatief — gebaseerd op spotprijs van {fmt(spot)} €/g {material === "gold" ? `× ${(purity * 100).toFixed(1)}% zuiverheid` : "× 92.5% (sterling)"}.
          Werkelijke opbrengst is afhankelijk van stempel, kwaliteit en onderhandeling.
        </p>
      </div>
    </div>
  );
}

// ─────────── FAQ ───────────
function FAQ({ items }) {
  const [open, setOpen] = useState(0);
  return (
    <div className="faq-list">
      {items.map((it, i) => (
        <div key={i} className={`faq-item ${open === i ? "open" : ""}`}>
          <div className="faq-q" onClick={() => setOpen(open === i ? -1 : i)}>
            <h3>{it.q}</h3>
            <span className="pm">+</span>
          </div>
          <div className="faq-a"><div className="inner">{it.a}</div></div>
        </div>
      ))}
    </div>
  );
}

// ─────────── Topstrip ───────────
function TopStrip({ current = 125.66, change = 1.34 }) {
  return (
    <div className="topstrip">
      <div className="wrap topstrip-inner">
        <div className="tick">
          <span className="dot"></span>
          <span>LIVE · GOUD 999 · €{current.toFixed(2)}/g</span>
          <span className="sep">·</span>
          <span style={{ color: change >= 0 ? "#9BE3B5" : "#E59B97" }}>
            {change >= 0 ? "▲" : "▼"} {Math.abs(change).toFixed(2)}%
          </span>
        </div>
        <div>ZILVER · €1,18/g  ·  ZWOLLE</div>
        <div>BEL 038 — 421 06 88</div>
      </div>
    </div>
  );
}

// ─────────── Brand / Nav ───────────
function Brand({ inverted = false }) {
  return (
    <a className="brand" href="index.html" style={inverted ? { color: "var(--paper)" } : null}>
      <span>Goudmeijer</span>
      <span className="mark">·</span>
      <small>est. 2014</small>
    </a>
  );
}

function MainNav({ active }) {
  const items = [
    { href: "diensten.html", label: "Diensten" },
    { href: "index.html#werkwijze", label: "Werkwijze" },
    { href: "index.html#over", label: "Over" },
    { href: "index.html#faq", label: "Vragen" },
    { href: "#", label: "Contact" },
  ];
  return (
    <nav className="main wrap">
      <Brand />
      <ul>
        {items.map((it) => (
          <li key={it.label}><a href={it.href} style={active === it.label ? { color: "var(--gold-deep)" } : null}>{it.label}</a></li>
        ))}
      </ul>
      <a className="nav-cta" href="afspraak-maken.html">
        Afspraak maken <span className="arr">→</span>
      </a>
    </nav>
  );
}

// ─────────── Footer ───────────
function Footer() {
  return (
    <footer>
      <div className="wrap">
        <div className="top">
          <div className="brand-block">
            <Brand inverted />
            <p>Onafhankelijke taxatie en verkoopbegeleiding van goud, zilver en sieraden. Wij kopen zelf niet in — uw belang is ons enige belang.</p>
          </div>
          <div>
            <h4>Diensten</h4>
            <ul>
              <li><a href="diensten.html">Taxatie</a></li>
              <li><a href="diensten.html">Verkoopbegeleiding</a></li>
              <li><a href="diensten.html">Erfenis &amp; nalatenschap</a></li>
              <li><a href="diensten.html">Tweede mening</a></li>
            </ul>
          </div>
          <div>
            <h4>Kantoor</h4>
            <ul>
              <li>Diezerstraat 88</li>
              <li>8011 RK Zwolle</li>
              <li>038 — 421 06 88</li>
              <li>hallo@goudmeijer.nl</li>
            </ul>
          </div>
          <div>
            <h4>Openingstijden</h4>
            <ul>
              <li>Di — Vr · 10—17</li>
              <li>Za · 10—15</li>
              <li>Of op afspraak</li>
            </ul>
          </div>
        </div>
        <div className="bot">
          <span>© 2026 Goudmeijer · KvK 60.142.881</span>
          <span>Privacy · Voorwaarden · Klachtenregeling</span>
        </div>
      </div>
    </footer>
  );
}

// ─────────── Trust strip ───────────
function TrustStrip() {
  const items = [
    { g: "✓", t1: "Wij kopen zelf niet in", t2: "Geen belangenverstrengeling" },
    { g: "₠", t1: "Vaste prijs per taxatie", t2: "Vanaf € 75,—" },
    { g: "✱", t1: "10 jaar specialist", t2: "FGS &amp; FTMV gecertificeerd" },
    { g: "→", t1: "Begeleiding tot verkoop", t2: "Hogere opbrengst, gemiddeld 18%" },
  ];
  return (
    <div className="trust-strip">
      <div className="wrap trust-strip-inner">
        {items.map((it, i) => (
          <div key={i} className="trust-item">
            <div className="glyph">{it.g}</div>
            <div>
              <span className="t1" dangerouslySetInnerHTML={{ __html: it.t1 }}></span>
              <span className="t2" dangerouslySetInnerHTML={{ __html: it.t2 }}></span>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Object.assign(window, {
  PriceChart, Calculator, FAQ, TopStrip, Brand, MainNav, Footer, TrustStrip,
  useReveal, CountUp,
});
