/* ============================================================
   Camillo De Vincentis — Portfolio app (IT / EN)
   ============================================================ */
const { useState, useEffect, useRef } = React;
const P = window.PORTFOLIO;

/* ---------- wordmark logo ---------- */
function Logo({ name, className }) {
  return <span className={"logo " + (className || "")}>{name}</span>;
}

/* ---------- custom cursor ---------- */
function Cursor() {
  const dot = useRef(null), ring = useRef(null);
  useEffect(() => {
    if (window.matchMedia("(pointer: coarse)").matches) return;
    let rx = innerWidth / 2, ry = innerHeight / 2, x = rx, y = ry;
    const move = (e) => {
      x = e.clientX; y = e.clientY;
      if (dot.current) dot.current.style.transform = `translate(${x}px,${y}px) translate(-50%,-50%)`;
    };
    const raf = () => {
      rx += (x - rx) * 0.18; ry += (y - ry) * 0.18;
      if (ring.current) ring.current.style.transform = `translate(${rx}px,${ry}px) translate(-50%,-50%)`;
      requestAnimationFrame(raf);
    };
    const over = (e) => {
      const h = e.target.closest("a,button,.work-item,.skill-cell,[data-hover]");
      if (ring.current) ring.current.classList.toggle("hovering", !!h);
    };
    addEventListener("mousemove", move);
    addEventListener("mouseover", over);
    requestAnimationFrame(raf);
    return () => { removeEventListener("mousemove", move); removeEventListener("mouseover", over); };
  }, []);
  return (<>
    <div className="cursor-dot" ref={dot}></div>
    <div className="cursor-ring" ref={ring}></div>
  </>);
}

/* ---------- scroll progress ---------- */
function Progress() {
  const el = useRef(null);
  useEffect(() => {
    const on = () => {
      const h = document.documentElement;
      const p = h.scrollTop / (h.scrollHeight - h.clientHeight);
      if (el.current) el.current.style.width = (p * 100) + "%";
    };
    addEventListener("scroll", on, { passive: true }); on();
    return () => removeEventListener("scroll", on);
  }, []);
  return <div className="progress" ref={el}></div>;
}

/* ---------- reveal on scroll ---------- */
function useReveal(dep) {
  useEffect(() => {
    const els = document.querySelectorAll(".reveal:not(.in)");
    const io = new IntersectionObserver((ents) => {
      ents.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } });
    }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" });
    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
  }, [dep]);
}

/* ---------- animated counter ---------- */
function Counter({ to, suf, raw }) {
  const ref = useRef(null);
  const [n, setN] = useState(0);
  useEffect(() => {
    let done = false;
    const io = new IntersectionObserver((ents) => {
      if (ents[0].isIntersecting && !done) {
        done = true;
        const dur = 1400, t0 = performance.now();
        const tick = (t) => {
          const p = Math.min(1, (t - t0) / dur);
          const e = 1 - Math.pow(1 - p, 3);
          setN(Math.round(to * e));
          if (p < 1) requestAnimationFrame(tick);
        };
        requestAnimationFrame(tick);
      }
    }, { threshold: 0.5 });
    if (ref.current) io.observe(ref.current);
    return () => io.disconnect();
  }, [to]);
  const txt = raw ? String(n) : n.toLocaleString("it-IT");
  return <span ref={ref}>{txt}<span className="suf">{suf}</span></span>;
}

/* ---------- hero interactive grid ---------- */
function HeroGrid() {
  const cv = useRef(null);
  useEffect(() => {
    const canvas = cv.current, ctx = canvas.getContext("2d");
    let w, h, dpr = Math.min(2, devicePixelRatio || 1);
    let mx = -9999, my = -9999, raf;
    const gap = 38;
    const resize = () => {
      w = canvas.clientWidth; h = canvas.clientHeight;
      canvas.width = w * dpr; canvas.height = h * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };
    const accent = () => getComputedStyle(document.body).getPropertyValue("--accent") || "#c4f542";
    const draw = () => {
      ctx.clearRect(0, 0, w, h);
      const cols = Math.ceil(w / gap), rows = Math.ceil(h / gap);
      const acc = accent().trim();
      for (let i = 0; i <= cols; i++) {
        for (let j = 0; j <= rows; j++) {
          const x = i * gap, y = j * gap;
          const dx = x - mx, dy = y - my;
          const dist = Math.sqrt(dx * dx + dy * dy);
          const r = Math.max(0, 1 - dist / 220);
          if (r > 0.02) {
            ctx.fillStyle = acc;
            ctx.globalAlpha = r * 0.9;
            ctx.beginPath();
            ctx.arc(x, y, 1 + r * 2.6, 0, Math.PI * 2);
            ctx.fill();
          } else {
            ctx.fillStyle = "rgba(255,255,255,0.07)";
            ctx.globalAlpha = 1;
            ctx.fillRect(x - 0.5, y - 0.5, 1, 1);
          }
        }
      }
      ctx.globalAlpha = 1;
      raf = requestAnimationFrame(draw);
    };
    const move = (e) => { const r = canvas.getBoundingClientRect(); mx = e.clientX - r.left; my = e.clientY - r.top; };
    const leave = () => { mx = -9999; my = -9999; };
    resize(); draw();
    addEventListener("resize", resize);
    addEventListener("mousemove", move);
    canvas.addEventListener("mouseleave", leave);
    return () => { cancelAnimationFrame(raf); removeEventListener("resize", resize); removeEventListener("mousemove", move); };
  }, []);
  return <canvas ref={cv}></canvas>;
}

/* ---------- nav ---------- */
function Nav({ d }) {
  return (
    <nav className="nav">
      <a className="brand" href="#top">CDV<span style={{ color: "var(--accent)" }}>.</span></a>
      <div className="nav-right">
        <div className="links">
          <a href="#work">{d.ui.nav.work}</a>
          <a href="#path">{d.ui.nav.path}</a>
          <a href="#skills">{d.ui.nav.skills}</a>
          <a href="#about">{d.ui.nav.about}</a>
          <a href="#contact">{d.ui.nav.contact}</a>
        </div>
      </div>
    </nav>
  );
}

/* ---------- hero ---------- */
function Hero({ d }) {
  const titleRef = useRef(null);
  useEffect(() => {
    const t = setTimeout(() => titleRef.current && titleRef.current.classList.add("in"), 180);
    return () => clearTimeout(t);
  }, []);
  return (
    <header className="hero" id="top">
      <HeroGrid />
      <div className="hero-grid-fade"></div>
      <div className="wrap">
        <div className="hero-meta">
          <span className="eyebrow">{d.role}</span>
          <span className="eyebrow" style={{ textTransform: "none" }}>{d.location} · Est. {d.since}</span>
        </div>
        <h1 className="hero-title" ref={titleRef}>
          <span className="line"><span>Camillo</span></span>
          <span className="line"><span className="o">De&nbsp;</span><span className="accent">Vincentis</span></span>
        </h1>
        <div className="hero-bottom">
          <p className="hero-lede">{d.lede}</p>
          <div className="scroll-cue"><span className="bar"></span>{d.ui.scroll}</div>
        </div>
      </div>
    </header>
  );
}

/* ---------- logo marquee (employers + clients) ---------- */
function LogoWall() {
  const items = [...P.brands, ...P.brands];
  return (
    <div className="marquee" aria-hidden="true">
      <div className="marquee-track">
        {items.map((m, i) => <Logo key={i} name={m} />)}
      </div>
    </div>
  );
}

/* ---------- manifesto ---------- */
function Manifesto({ d }) {
  const ref = useRef(null);
  useEffect(() => {
    const words = ref.current.querySelectorAll(".word");
    const on = () => {
      const r = ref.current.getBoundingClientRect();
      const start = innerHeight * 0.8, end = innerHeight * 0.2;
      const prog = Math.min(1, Math.max(0, (start - r.top) / (start - end + r.height)));
      const active = Math.floor(prog * words.length * 1.3);
      words.forEach((wd, i) => { wd.style.opacity = i < active ? "1" : "0.22"; });
    };
    addEventListener("scroll", on, { passive: true }); on();
    return () => removeEventListener("scroll", on);
  }, [d]);
  return (
    <section className="manifesto wrap" ref={ref}>
      <p>
        {d.manifesto.map((wd, i) => (
          <span key={i} className={"word " + (wd.c || "")} data-i={i} style={{ opacity: 0.22, transition: "opacity .4s" }}>
            {wd.t}{" "}
          </span>
        ))}
      </p>
    </section>
  );
}

/* ---------- stats ---------- */
function Stats({ d }) {
  return (
    <section className="wrap">
      <div className="stats">
        {d.stats.map((s, i) => (
          <div className="stat reveal" data-d={i} key={i}>
            <div className="n"><Counter to={s.n} suf={s.suf} raw={s.raw} /></div>
            <div className="l">{s.label}</div>
          </div>
        ))}
      </div>
    </section>
  );
}

/* ---------- work ---------- */
function Work({ d }) {
  return (
    <section className="sec wrap" id="work">
      <div className="sec-head reveal">
        <span className="sec-num">{d.ui.secWork}</span>
        <h2>{lang_h2(d)}</h2>
      </div>
      <div className="work-list">
        {d.work.map((p, i) => (
          <div className="work-item reveal" data-d={i % 3} key={i}>
            <div className="work-row">
              <span className="idx">{p.idx}</span>
              <div>
                <div className="title">{p.title}</div>
                <span className="client">{p.client}</span>
              </div>
              <div className="tags">
                {p.tags.map((t, j) => <span className="tag" key={j}>{t}</span>)}
              </div>
            </div>
            <div className="work-viz">
              <div className="work-viz-inner">
                <div className="ph"><span className="ph-label">{p.label}</span></div>
              </div>
            </div>
          </div>
        ))}
      </div>
      <p className="muted" style={{ fontFamily: "var(--font-mono)", fontSize: 12, marginTop: 24 }}>
        {d.ui.ndaNote}
      </p>
    </section>
  );
}
function lang_h2(d) {
  return d.ui.secWork.includes("Lavori")
    ? <>Sistemi che <em>non possono</em> sbagliare.</>
    : <>Systems that <em>can't</em> get it wrong.</>;
}

/* ---------- timeline (with client logos) ---------- */
function Timeline({ d }) {
  return (
    <section className="sec wrap" id="path">
      <div className="sec-head reveal">
        <span className="sec-num">{d.ui.secPath}</span>
        <h2>{d.ui.secPath.includes("Percorso")
          ? <>Tre aziende, <em>una</em> traiettoria.</>
          : <>Three companies, <em>one</em> trajectory.</>}</h2>
      </div>
      <div className="tl">
        {d.timeline.map((t, i) => (
          <div className={"tl-item reveal" + (t.now ? " now" : "")} data-d={i % 3} key={i}>
            <div className="yr">{t.yr}</div>
            <div>
              <div className="role">{t.role}{t.now && <span className="badge">{d.ui.now}</span>}</div>
              <div className="co"><Logo name={t.co} className="co-logo" /></div>
              <p className="desc">{t.desc}</p>
              <div className="client-logos">
                <span className="cl-label">{d.ui.clientsLabel}</span>
                <div className="cl-row">
                  {t.clients.map((c, j) => <Logo key={j} name={c} />)}
                </div>
              </div>
            </div>
          </div>
        ))}
      </div>
    </section>
  );
}

/* ---------- skills ---------- */
function Skills({ d }) {
  return (
    <section className="sec wrap" id="skills">
      <div className="sec-head reveal">
        <span className="sec-num">{d.ui.secSkills}</span>
        <h2>{d.ui.secSkills.includes("Competenze")
          ? <>Tutto lo <em>stack</em>, con metodo.</>
          : <>The whole <em>stack</em>, with method.</>}</h2>
      </div>
      <div className="skills-grid">
        {d.skills.map((s, i) => (
          <div className="skill-cell reveal" data-d={i % 2} key={i}>
            <span className="k">{s.k}</span>
            <h3>{s.h}</h3>
            <p>{s.p}</p>
            <div className="chips">{s.chips.map((c, j) => <span className="chip" key={j}>{c}</span>)}</div>
          </div>
        ))}
      </div>
    </section>
  );
}

/* ---------- about ---------- */
function About({ d }) {
  const a = d.about;
  return (
    <section className="sec wrap" id="about">
      <div className="sec-head reveal">
        <span className="sec-num">{d.ui.secAbout}</span>
      </div>
      <div className="about">
        <div>
          <p className="about-lead reveal">{a.lead}</p>
        </div>
        <div className="about-body reveal" data-d="1">
          {a.body.map((p, i) => <p key={i}>{p}</p>)}
          <div className="about-facts">
            {a.facts.map((f, i) => (
              <div className="row" key={i}><span className="k">{f.k}</span><span className="v">{f.v}</span></div>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---------- contact ---------- */
function Contact({ d }) {
  return (
    <section className="contact wrap" id="contact">
      <div className="reveal">
        <span className="eyebrow" style={{ justifyContent: "center", display: "flex" }}>{d.ui.contactKicker}</span>
        <div className="big" style={{ marginTop: 28 }}>
          <a href={"mailto:" + P.email}>{d.ui.contactBig[0]}<br />{d.ui.contactBig[1]}</a>
        </div>
        <p className="contact-sub">{d.ui.contactSub}</p>
        <div className="contact-row">
          <a className="btn solid" href={"mailto:" + P.email}><span>{d.ui.contactBtn}</span><span>→</span></a>
        </div>
        <div className="contact-links">
          {P.links.map((l, i) => <a href={l.href} key={i} target={l.href.startsWith("http") ? "_blank" : undefined}>{l.label}</a>)}
        </div>
      </div>
    </section>
  );
}

/* ---------- tweaks ---------- */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#5b8cff",
  "motion": true,
  "grain": true
}/*EDITMODE-END*/;

const ACCENTS = {
  "#c4f542": "oklch(0.86 0.19 128)",
  "#5b8cff": "oklch(0.72 0.16 262)",
  "#ff6a3d": "oklch(0.72 0.18 40)",
  "#b388ff": "oklch(0.74 0.16 300)",
  "#ffffff": "oklch(0.97 0 0)",
};
const ACCENT_INK = {
  "#c4f542": "oklch(0.22 0.04 128)",
  "#5b8cff": "oklch(0.18 0.04 262)",
  "#ff6a3d": "oklch(0.18 0.04 40)",
  "#b388ff": "oklch(0.18 0.04 300)",
  "#ffffff": "oklch(0.15 0 0)",
};

function App() {
  // Language is locked to English for now. The Italian copy is preserved in
  // data.js (P.it) — to re-enable the IT/EN toggle, restore the lang state +
  // the language button in <Nav>.
  const lang = "en";
  const d = P[lang];
  useReveal(lang);

  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  useEffect(() => {
    const acc = ACCENTS[t.accent] || ACCENTS["#5b8cff"];
    const ink = ACCENT_INK[t.accent] || ACCENT_INK["#5b8cff"];
    document.body.style.setProperty("--accent", acc);
    document.body.style.setProperty("--accent-ink", ink);
    const m = acc.match(/oklch\(([^)]+)\)/);
    if (m) document.body.style.setProperty("--accent-soft", `oklch(${m[1]} / 0.12)`);
  }, [t.accent]);
  useEffect(() => { document.body.classList.toggle("no-motion", !t.motion); }, [t.motion]);
  useEffect(() => { document.body.style.setProperty("--grain-op", t.grain ? "0.035" : "0"); }, [t.grain]);

  return (<>
    <Cursor />
    <Progress />
    <Nav d={d} />
    <Hero d={d} />
    <LogoWall />
    <Manifesto d={d} />
    <Stats d={d} />
    <Work d={d} />
    <Timeline d={d} />
    <Skills d={d} />
    <About d={d} />
    <Contact d={d} />
    <footer className="foot">
      <span>© {new Date().getFullYear()} Camillo De Vincentis</span>
      <span>{d.ui.footRight}</span>
      <span>{d.ui.footNote}</span>
    </footer>

    <TweaksPanel>
      <TweakSection label="Accento" />
      <TweakColor label="Colore" value={t.accent} options={Object.keys(ACCENTS)} onChange={(v) => setTweak("accent", v)} />
      <TweakSection label="Esperienza" />
      <TweakToggle label="Animazioni" value={t.motion} onChange={(v) => setTweak("motion", v)} />
      <TweakToggle label="Grana / texture" value={t.grain} onChange={(v) => setTweak("grain", v)} />
    </TweaksPanel>
  </>);
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
