// cv-app.jsx — main React app for the CV site
// Aesthetic: modern + bold, warm dark default, Instrument Serif display + Geist body + JetBrains Mono accents.
// Single accent in oklch — varied via Tweaks. Bilingual EL/EN. All section content from window.CV / window.UI.

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

const TWEAKS_DEFAULTS = /*EDITMODE-BEGIN*/{
  "fontPair": "serif-sans",
  "density": "compact",
  "animation": "subtle",
  "orbs": true,
  "lang": "en"
}/*EDITMODE-END*/;

// Single brand accent — a measured forest green, suitable for executive tone.
const ACCENT = { color: "oklch(0.52 0.10 155)", ink: "#ffffff" };

const FONT_PAIRS = {
  "serif-sans": {
    name: "Serif × Sans",
    display: "'Instrument Serif', 'Times New Roman', serif",
    body:    "'Geist', ui-sans-serif, system-ui, sans-serif",
    mono:    "'JetBrains Mono', ui-monospace, monospace",
    italicDisplay: true,
  },
  "sans-mono": {
    name: "Grotesk × Mono",
    display: "'Space Grotesk', ui-sans-serif, system-ui, sans-serif",
    body:    "'Space Grotesk', ui-sans-serif, system-ui, sans-serif",
    mono:    "'JetBrains Mono', ui-monospace, monospace",
    italicDisplay: false,
  },
  "editorial": {
    name: "Editorial",
    display: "'Newsreader', 'Times New Roman', serif",
    body:    "'Newsreader', 'Times New Roman', serif",
    mono:    "'JetBrains Mono', ui-monospace, monospace",
    italicDisplay: true,
  },
};

const DENSITY = {
  compact:    { sectionPad: 64,  blockGap: 18, base: 15.5 },
  regular:    { sectionPad: 100, blockGap: 24, base: 16.5 },
  comfortable:{ sectionPad: 140, blockGap: 32, base: 17.5 },
};

// ── helpers ───────────────────────────────────────────────────────────────
const t = (val, lang) => (val == null ? "" : (typeof val === "string" ? val : val[lang] ?? val.en));

function useReveal(animation) {
  // CSS-only entrance: setting data-in="1" on attach makes the [data-in="1"]
  // CSS rule apply, which runs the cv-enter keyframes once. This is rAF- and
  // IntersectionObserver-independent, so it fires even in iframes whose
  // visibilityState is "hidden". Animation level handled in CSS via
  // :root[data-anim="off"].
  return useCallback((el) => {
    if (!el) return;
    el.dataset.in = "1";
  }, [animation]);
}

function useActiveSection(ids) {
  const [active, setActive] = useState(ids[0]);
  useEffect(() => {
    const obs = new IntersectionObserver((entries) => {
      const visible = entries
        .filter((e) => e.isIntersecting)
        .sort((a, b) => b.intersectionRatio - a.intersectionRatio);
      if (visible[0]) setActive(visible[0].target.id);
    }, { rootMargin: "-40% 0px -45% 0px", threshold: [0, 0.25, 0.5, 0.75, 1] });
    ids.forEach((id) => {
      const el = document.getElementById(id);
      if (el) obs.observe(el);
    });
    return () => obs.disconnect();
  }, [ids.join(",")]);
  return active;
}

// ── chrome: top nav + tools ───────────────────────────────────────────────
const NAV_IDS = ["about", "skills", "education", "projects", "certs", "contact"];

function TopNav({ lang, active, onLang, onPrint }) {
  const initials = t(window.CV.initials, lang);

  return (
    <header className="cv-nav">
      <a href="#top" className="cv-nav-brand">
        <span className="cv-monogram-sm">{initials}</span>
        <span className="cv-nav-name">{t(window.CV.name, lang)}</span>
      </a>
      <nav className="cv-nav-links">
        {NAV_IDS.map((id) => (
          <a key={id} href={`#${id}`} data-active={active === id ? "1" : "0"}>
            <span>{t(window.UI.nav[id === "certs" ? "certs" : id], lang)}</span>
          </a>
        ))}
      </nav>
      <div className="cv-nav-tools">
        <div className="cv-langtoggle" role="radiogroup" aria-label="Language">
          <button onClick={() => onLang("en")} data-on={lang === "en" ? "1" : "0"}>EN</button>
          <button onClick={() => onLang("el")} data-on={lang === "el" ? "1" : "0"}>EL</button>
        </div>
        <button className="cv-icon-btn" onClick={onPrint} title="Print / Save PDF" aria-label="Print">
          <PrintIcon />
        </button>
      </div>
    </header>
  );
}

const PrintIcon = () => (
  <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
    <path d="M6 9V3h12v6" /><rect x="4" y="9" width="16" height="9" rx="1.5" /><path d="M7 14h10v6H7z" />
  </svg>
);
const ArrowRight = () => (
  <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
    <path d="M5 12h14M13 5l7 7-7 7" />
  </svg>
);
const Download = () => (
  <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
    <path d="M12 3v13M6 12l6 6 6-6M4 21h16" />
  </svg>
);
const Dot = () => <span className="cv-dot">·</span>;

// ── sections ──────────────────────────────────────────────────────────────
function Hero({ lang, density, onReveal }) {
  const C = window.CV;
  const U = window.UI;
  const initials = t(C.initials, lang);
  const otherLang = lang === "en" ? "el" : "en";
  return (
    <section id="top" className="cv-hero">
      <div className="cv-hero-grid">
        <div className="cv-hero-meta" ref={onReveal}>
          <div className="cv-eyebrow">
            <span className="cv-pulse"></span>
            <span>{t(C.available, lang)}</span>
            <Dot />
            <span>{t(C.contact.location, lang)}</span>
          </div>
        </div>

        <h1 className="cv-hero-name" ref={onReveal}>
          <span className="cv-line">{t(C.name, lang)}</span>
        </h1>

        <div className="cv-hero-roleblock" ref={onReveal}>
          <div className="cv-hero-role">
            <span className="cv-role-bar"></span>
            <span>{t(C.role, lang)}</span>
          </div>
          <p className="cv-hero-tagline">{t(C.tagline, lang)}</p>
          <div className="cv-hero-ctas">
            <a href="#projects" className="cv-btn cv-btn-primary">
              {t(U.hero.cta1, lang)} <ArrowRight />
            </a>
            <a href={t(C.pdf, lang)} download={t(C.pdfDownload, lang)} className="cv-btn cv-btn-ghost">
              {t(U.hero.cta2, lang)} <Download />
            </a>
          </div>
          <a
            href={t(C.pdf, otherLang)}
            download={t(C.pdfDownload, otherLang)}
            className="cv-hero-pdf-alt"
          >
            {t(U.hero.cta2other, lang)}
          </a>
        </div>

        <div className="cv-hero-facts" ref={onReveal}>
          {C.facts.map((f, i) => (
            <div key={i} className="cv-fact">
              <div className="cv-fact-value">{f.value}</div>
              <div className="cv-fact-label cv-mono">{t(f.label, lang)}</div>
            </div>
          ))}
        </div>

        <div className="cv-hero-aside" ref={onReveal}>
          <div className="cv-monogram">
            <svg viewBox="0 0 200 200" className="cv-monogram-ring" aria-hidden="true">
              <defs>
                <path id="cv-ring-path" d="M100,100 m-86,0 a86,86 0 1,1 172,0 a86,86 0 1,1 -172,0" />
              </defs>
              <circle cx="100" cy="100" r="92" fill="none" stroke="currentColor" strokeOpacity="0.1" strokeWidth="0.5" />
              <text className="cv-ring-text">
                <textPath href="#cv-ring-path" startOffset="0">
                  · OPEN TO WORK · {new Date().getFullYear()} · MBA · BUSINESS ADMINISTRATION 
                </textPath>
              </text>
            </svg>
            <span className="cv-monogram-letters">{initials}</span>
          </div>
        </div>

        <div className="cv-hero-scroll" ref={onReveal}>
          <span className="cv-mono">↓ {t(U.hero.scroll, lang)}</span>
        </div>
      </div>
    </section>
  );
}

function SectionTitle({ label, kicker }) {
  return (
    <div className="cv-section-head">
      <div className="cv-mono cv-section-kicker">{label}</div>
      {kicker && <div className="cv-section-sub">{kicker}</div>}
    </div>
  );
}

function About({ lang, onReveal }) {
  return (
    <section id="about" className="cv-section">
      <SectionTitle label={t(window.UI.sections.about, lang)} />
      <div className="cv-about-grid">
        <div className="cv-about-quote" ref={onReveal}>
          <span className="cv-q-mark">“</span>
          <p>
            {lang === "el"
              ? <>Συνδυάζω <em>food‑systems thinking</em> με σύγχρονη διοίκηση και τεχνολογία.</>
              : <>I bridge <em>food‑systems thinking</em> with modern management and technology.</>}
          </p>
        </div>
        <div className="cv-about-body" ref={onReveal}>
          {t(window.CV.about, lang).map((p, i) => <p key={i}>{p}</p>)}
        </div>
      </div>
    </section>
  );
}

function Skills({ lang, onReveal }) {
  const groups = t(window.CV.skills, lang);
  return (
    <section id="skills" className="cv-section">
      <SectionTitle label={t(window.UI.sections.skills, lang)} />
      <div className="cv-skills-grid">
        {groups.map((g, i) => (
          <div key={i} className="cv-skill-group" ref={onReveal} style={{ "--i": i }}>
            <h3 className="cv-skill-h">{g.group}</h3>
            <div className="cv-skill-tags">
              {g.items.map((s) => <span key={s} className="cv-tag">{s}</span>)}
            </div>
          </div>
        ))}
      </div>
    </section>
  );
}

function Education({ lang, onReveal }) {
  const items = window.CV.education;
  return (
    <section id="education" className="cv-section">
      <SectionTitle label={t(window.UI.sections.education, lang)} />
      <div className="cv-edu-list">
        {items.map((e, i) => (
          <article key={i} className="cv-edu-item" ref={onReveal}>
            <div className="cv-edu-years">
              <span className="cv-edu-from">{e.from}</span>
              <span className="cv-edu-to">→ {e.to}</span>
            </div>
            <div className="cv-edu-body">
              <h3 className="cv-edu-degree">{t(e.degree, lang)}</h3>
              <div className="cv-edu-school">{t(e.school, lang)}</div>
              <div className="cv-edu-meta cv-mono">
                <span>{t(e.where, lang)}</span><Dot />
                <span>EQF {e.eqf}</span><Dot />
                <span>{e.site}</span>
              </div>
            </div>
            <div className="cv-edu-rule"></div>
          </article>
        ))}
      </div>
    </section>
  );
}

function Projects({ lang, onReveal }) {
  return (
    <section id="projects" className="cv-section">
      <SectionTitle label={t(window.UI.sections.projects, lang)} />
      <div className="cv-projects">
        {window.CV.projects.map((p, i) => (
          <ProjectCard key={i} p={p} lang={lang} idx={i} onReveal={onReveal} />
        ))}
      </div>
    </section>
  );
}

function ProjectCard({ p, lang, idx, onReveal }) {
  const ref = useRef(null);
  const [tilt, setTilt] = useState({ x: 0, y: 0 });
  const onMove = (e) => {
    const r = ref.current.getBoundingClientRect();
    const px = (e.clientX - r.left) / r.width - 0.5;
    const py = (e.clientY - r.top) / r.height - 0.5;
    setTilt({ x: -py * 6, y: px * 8 });
  };
  const onLeave = () => setTilt({ x: 0, y: 0 });

  return (
    <article className="cv-proj" ref={(el) => { ref.current = el; onReveal(el); }}
             onMouseMove={onMove} onMouseLeave={onLeave}
             style={{ transform: `perspective(1200px) rotateX(${tilt.x}deg) rotateY(${tilt.y}deg)` }}>
      <div className="cv-proj-thumb" aria-hidden="true">
        <div className="cv-proj-thumb-inner">
          <span className="cv-mono">{`/${(idx + 1).toString().padStart(2, "0")}`}</span>
          <ProjectGlyph kind={idx} />
        </div>
      </div>
      <div className="cv-proj-body">
        <div className="cv-mono cv-proj-meta">
          <span>{t(p.kind, lang)}</span><Dot /><span>{p.year}</span>
        </div>
        <h3 className="cv-proj-title">{t(p.title, lang)}</h3>
        <p className="cv-proj-desc">{t(p.desc, lang)}</p>
        <div className="cv-proj-tags">
          {p.tags.map((tg) => <span key={tg} className="cv-tag cv-tag-sm">{tg}</span>)}
        </div>
        {p.pdf && (
          <a href={p.pdf} target="_blank" rel="noopener" className="cv-btn cv-btn-ghost cv-proj-link">
            {t(window.UI.projects.pdf, lang)} <ArrowRight />
          </a>
        )}
      </div>
    </article>
  );
}

function ProjectGlyph({ kind }) {
  // Abstract typographic glyphs — no fake screenshots, no AI slop iconography.
  if (kind === 0) {
    return (
      <svg viewBox="0 0 200 140" className="cv-glyph">
        {Array.from({ length: 8 }).map((_, i) => (
          <circle key={i} cx={30 + i * 20} cy={70} r={4 + (i % 3) * 3}
                  fill="currentColor" opacity={0.25 + (i % 4) * 0.18} />
        ))}
        <path d="M 30 70 Q 100 20 170 70" stroke="currentColor" strokeWidth="1" fill="none" opacity="0.5" />
        <text x="100" y="120" textAnchor="middle" className="cv-glyph-text">A · I</text>
      </svg>
    );
  }
  return (
    <svg viewBox="0 0 200 140" className="cv-glyph">
      {Array.from({ length: 6 }).map((_, i) => (
        <rect key={i} x={20 + i * 28} y={40 + (i % 2) * 18} width="20" height={50 - (i % 3) * 10}
              fill="currentColor" opacity={0.2 + (i % 4) * 0.15} />
      ))}
      <text x="100" y="120" textAnchor="middle" className="cv-glyph-text">F · Q</text>
    </svg>
  );
}

function Certifications({ lang, onReveal }) {
  const [open, setOpen] = useState(null);
  return (
    <section id="certs" className="cv-section">
      <SectionTitle label={t(window.UI.sections.certs, lang)} />
      <div className="cv-certs">
        {window.CV.certifications.map((c, i) => {
          const isOpen = open === i;
          return (
            <div key={i} className="cv-cert" data-open={isOpen ? "1" : "0"} ref={onReveal}>
              <button className="cv-cert-row" onClick={() => setOpen(isOpen ? null : i)}>
                <span className="cv-cert-year cv-mono">{c.year}</span>
                <span className="cv-cert-title">{t(c.title, lang)}</span>
                <span className="cv-cert-org">{t(c.org, lang)}</span>
                <span className="cv-cert-mode cv-mono">{t(c.mode, lang)}</span>
                <span className="cv-cert-chev">{isOpen ? "−" : "+"}</span>
              </button>
              {isOpen && c.modules && (
                <div className="cv-cert-detail">
                  <ul>{t(c.modules, lang).map((m, j) => <li key={j}>{m}</li>)}</ul>
                </div>
              )}
            </div>
          );
        })}
      </div>
    </section>
  );
}

function Languages({ lang, onReveal }) {
  return (
    <section id="languages" className="cv-section">
      <SectionTitle label={t(window.UI.sections.languages, lang)} />
      <div className="cv-langs" ref={onReveal}>
        {window.CV.languages.map((l, i) => (
          <div key={i} className="cv-lang">
            <div className="cv-lang-name">{t(l.name, lang)}</div>
            <div className="cv-lang-mark cv-mono">{l.mark}</div>
            <div className="cv-lang-level">{t(l.level, lang)}</div>
          </div>
        ))}
        <div className="cv-langs-footnote cv-mono">
          A1·A2 basic — B1·B2 independent — C1·C2 proficient (CEFR)
        </div>
      </div>
    </section>
  );
}

function Contact({ lang, onReveal }) {
  const U = window.UI.contact;
  const C = window.CV.contact;
  const mailto = `mailto:${C.email}?subject=${encodeURIComponent(t(U.subject, lang))}`;

  return (
    <section id="contact" className="cv-section">
      <SectionTitle label={t(window.UI.sections.contact, lang)} />
      <div className="cv-contact-grid">
        <div className="cv-contact-intro" ref={onReveal}>
          <p className="cv-contact-lead">{t(U.intro, lang)}</p>
          <a href={mailto} className="cv-btn cv-btn-primary cv-contact-cta">
            {t(U.cta, lang)} <ArrowRight />
          </a>
        </div>
        <ul className="cv-contact-links" ref={onReveal}>
          <li><span className="cv-mono">email</span><a href={mailto}>{C.email}</a></li>
          <li><span className="cv-mono">phone</span><a href={`tel:${C.phone.replace(/\s/g, "")}`}>{C.phone}</a></li>
          <li><span className="cv-mono">facebook</span><a href={`https://${C.facebook}`} target="_blank" rel="noopener">{C.facebook}</a></li>
          <li>
            <span className="cv-mono">cv</span>
            <span className="cv-contact-pdfs">
              <a href={window.CV.pdf.en} download={window.CV.pdfDownload.en}>{t(U.cvEn, lang)}</a>
              <Dot />
              <a href={window.CV.pdf.el} download={window.CV.pdfDownload.el}>{t(U.cvEl, lang)}</a>
            </span>
          </li>
        </ul>
      </div>
    </section>
  );
}

function Footer({ lang }) {
  return (
    <footer className="cv-footer">
      <div className="cv-mono">© {new Date().getFullYear()} · {t(window.CV.name, lang)}</div>
      <div className="cv-mono">{t(window.UI.footer.based, lang)} {t(window.CV.contact.location, lang)} · {t(window.UI.footer.built, lang)}</div>
    </footer>
  );
}

// ── background: connected orbs ────────────────────────────────────────────
function OrbsBackground() {
  // Slowly drifting points connected by hairlines when close. Canvas keeps
  // it cheap (~30 nodes) and lets us pulse opacity with --accent. Pauses
  // when the tab is hidden so it doesn't burn cycles.
  const ref = useRef(null);
  useEffect(() => {
    const cvs = ref.current;
    if (!cvs) return undefined;
    const ctx = cvs.getContext("2d");
    let raf = 0, w = 0, h = 0;
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    const N = Math.round(Math.min(70, Math.max(40, (window.innerWidth * window.innerHeight) / 38000)));
    const nodes = Array.from({ length: N }, () => ({
      x: Math.random(), y: Math.random(),
      vx: (Math.random() - 0.5) * 0.00004,
      vy: (Math.random() - 0.5) * 0.00004,
    }));
    const accent = getComputedStyle(document.documentElement).getPropertyValue("--accent-rgb").trim() || "60,120,80";
    const resize = () => {
      w = window.innerWidth; h = window.innerHeight;
      cvs.style.width = w + "px"; cvs.style.height = h + "px";
      cvs.width = w * dpr; cvs.height = h * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };
    resize();
    window.addEventListener("resize", resize);
    let last = performance.now();
    const loop = (now) => {
      const dt = Math.min(60, now - last); last = now;
      ctx.clearRect(0, 0, w, h);
      for (const n of nodes) {
        n.x += n.vx * dt; n.y += n.vy * dt;
        if (n.x < 0) { n.x = 0; n.vx = Math.abs(n.vx); }
        else if (n.x > 1) { n.x = 1; n.vx = -Math.abs(n.vx); }
        if (n.y < 0) { n.y = 0; n.vy = Math.abs(n.vy); }
        else if (n.y > 1) { n.y = 1; n.vy = -Math.abs(n.vy); }
      }
      // hairlines
      ctx.lineWidth = 0.6;
      for (let i = 0; i < N; i++) {
        for (let j = i + 1; j < N; j++) {
          const a = nodes[i], b = nodes[j];
          const dx = (a.x - b.x) * w, dy = (a.y - b.y) * h;
          const d = Math.hypot(dx, dy);
          if (d < 220) {
            const o = (1 - d / 220) * 0.22;
            ctx.strokeStyle = `rgba(${accent}, ${o})`;
            ctx.beginPath();
            ctx.moveTo(a.x * w, a.y * h);
            ctx.lineTo(b.x * w, b.y * h);
            ctx.stroke();
          }
        }
      }
      // orbs
      for (const n of nodes) {
        ctx.fillStyle = `rgba(${accent}, 0.55)`;
        ctx.beginPath();
        ctx.arc(n.x * w, n.y * h, 2.2, 0, Math.PI * 2);
        ctx.fill();
      }
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    const onVis = () => {
      if (document.hidden) cancelAnimationFrame(raf);
      else { last = performance.now(); raf = requestAnimationFrame(loop); }
    };
    document.addEventListener("visibilitychange", onVis);
    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("resize", resize);
      document.removeEventListener("visibilitychange", onVis);
    };
  }, []);
  return <canvas ref={ref} className="cv-orbs" aria-hidden="true" />;
}

function App() {
  const [tw, setTweak] = useTweaks(TWEAKS_DEFAULTS);
  const lang = tw.lang;
  const fp = FONT_PAIRS[tw.fontPair] || FONT_PAIRS["serif-sans"];
  const dens = DENSITY[tw.density] || DENSITY.compact;

  const reveal = useReveal(tw.animation);
  const active = useActiveSection(NAV_IDS);

  // Apply CSS variables to <html> so styles read them root-wide.
  useEffect(() => {
    const r = document.documentElement;
    r.style.setProperty("--accent", ACCENT.color);
    r.style.setProperty("--accent-ink", ACCENT.ink);
    r.style.setProperty("--font-display", fp.display);
    r.style.setProperty("--font-body", fp.body);
    r.style.setProperty("--font-mono", fp.mono);
    r.style.setProperty("--display-italic", fp.italicDisplay ? "italic" : "normal");
    r.style.setProperty("--section-pad", dens.sectionPad + "px");
    r.style.setProperty("--block-gap", dens.blockGap + "px");
    r.style.setProperty("--base-size", dens.base + "px");
    r.dataset.theme = "light";
    r.dataset.anim = tw.animation;
    r.lang = lang;
  }, [fp, dens, tw.animation, lang]);

  return (
    <>
      {tw.orbs && <OrbsBackground />}
      <TopNav
        lang={lang} active={active}
        onLang={(v) => setTweak("lang", v)}
        onPrint={() => window.print()}
      />
      <main className="cv-main">
        <Hero lang={lang} density={dens} onReveal={reveal} />
        <About lang={lang} onReveal={reveal} />
        <Skills lang={lang} onReveal={reveal} />
        <Education lang={lang} onReveal={reveal} />
        <Projects lang={lang} onReveal={reveal} />
        <Certifications lang={lang} onReveal={reveal} />
        <Languages lang={lang} onReveal={reveal} />
        <Contact lang={lang} onReveal={reveal} />
      </main>
      <Footer lang={lang} />

      <TweaksPanel title="Tweaks">
        <TweakSection label="Type">
          <TweakSelect
            label="Font pair" value={tw.fontPair}
            options={Object.entries(FONT_PAIRS).map(([k, v]) => ({ value: k, label: v.name }))}
            onChange={(v) => setTweak("fontPair", v)}
          />
        </TweakSection>
        <TweakSection label="Layout">
          <TweakRadio label="Density" value={tw.density}
            options={["compact", "regular", "comfortable"]}
            onChange={(v) => setTweak("density", v)} />
          <TweakRadio label="Animation" value={tw.animation}
            options={["off", "subtle", "lively"]}
            onChange={(v) => setTweak("animation", v)} />
          <TweakToggle label="Background orbs" value={tw.orbs}
            onChange={(v) => setTweak("orbs", v)} />
        </TweakSection>
        <TweakSection label="Language">
          <TweakRadio label="Locale" value={lang}
            options={[{ value: "en", label: "English" }, { value: "el", label: "Ελληνικά" }]}
            onChange={(v) => setTweak("lang", v)} />
        </TweakSection>
      </TweaksPanel>
    </>
  );
}

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