/* global React, ReactDOM, Frame, useTweaks, TweaksPanel, TweakSection, TweakSlider, TweakToggle, TweakColor, TweakRadio */

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

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#f4f1ea",
  "grain": 0.08,
  "motion": true,
  "scanlines": true,
  "heroLayout": "simple"
}/*EDITMODE-END*/;

/* ─────────────  Work data  ───────────── */

const WORKS = [
  { num:'01', title:'Annibal',         sub:'Spec Teaser · Wallyscar', yt:'gXfM4J00Qqs' },
  { num:'02', title:'LostJeel',        sub:'Spec Ad · LostJeel',      yt:'4WWhF4q_ruo' },
  { num:'03', title:'Boga Shhhh',      sub:'Spec Ad · Boga',          yt:'Gvk8XwSwhfw' },
  { num:'04', title:'Sexy Fruit',      sub:'Commercial · Dally',      yt:'NefqDH1XSQU' },
  { num:'05', title:'Short Movie POS', sub:'Dor Awards',                  yt:'evEIxpGc51Y' },
  { num:'06', title:'Generic Juice',   sub:'Spec Ad · Dally',         yt:'EANB5iBsWl0' },
];

const PROCESS = [
  { n:'I',   name:'Listen',     it:'Listen'     },
  { n:'II',  name:'Storyboard', it:'board'      },
  { n:'III', name:'Discuss',    it:'Discuss'    },
  { n:'IV',  name:'Refine',     it:'Refine'     },
  { n:'V',   name:'Generate',   it:'Generate'   },
  { n:'VI',  name:'Deliver',    it:'Deliver'    },
];

const MARQUEE = ['Commercials','Virals — if they earn it','Short films','Music videos','Title sequences','Things friends ask me to make at midnight'];

/* ─────────────  Cursor  ───────────── */

function Cursor() {
  const dot = useRef(null);
  const ring = useRef(null);
  useEffect(() => {
    let dx=0,dy=0,rx=0,ry=0,tx=0,ty=0;
    let raf;
    const onMove = (e) => { tx=e.clientX; ty=e.clientY; if(!raf) tick(); };
    const tick = () => {
      dx += (tx-dx)*0.55; dy += (ty-dy)*0.55;
      rx += (tx-rx)*0.18; ry += (ty-ry)*0.18;
      if (dot.current) dot.current.style.transform = `translate(${dx}px, ${dy}px) translate(-50%,-50%)`;
      if (ring.current) ring.current.style.transform = `translate(${rx}px, ${ry}px) translate(-50%,-50%)`;
      raf = requestAnimationFrame(tick);
    };
    const onOver = (e) => {
      const t = e.target.closest('a,button,input,textarea,select,[data-cursor]');
      if (!ring.current) return;
      ring.current.classList.remove('is-link','is-play');
      if (!t) return;
      const kind = t.getAttribute('data-cursor');
      if (kind === 'play') ring.current.classList.add('is-play');
      else ring.current.classList.add('is-link');
    };
    const onLeaveDoc = () => {
      dot.current?.classList.add('is-hide');
      ring.current?.classList.add('is-hide');
    };
    const onEnterDoc = () => {
      dot.current?.classList.remove('is-hide');
      ring.current?.classList.remove('is-hide');
    };
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseover', onOver);
    document.addEventListener('mouseleave', onLeaveDoc);
    document.addEventListener('mouseenter', onEnterDoc);
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseover', onOver);
      document.removeEventListener('mouseleave', onLeaveDoc);
      document.removeEventListener('mouseenter', onEnterDoc);
      cancelAnimationFrame(raf);
    };
  }, []);
  return (
    <>
      <div className="cur-dot" ref={dot} />
      <div className="cur-ring" ref={ring} />
    </>
  );
}

/* ─────────────  Magnetic wrapper  ───────────── */

function Magnetic({ children, strength = 0.35, className }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const x = e.clientX - (r.left + r.width/2);
      const y = e.clientY - (r.top + r.height/2);
      el.style.transform = `translate(${x*strength}px, ${y*strength}px)`;
    };
    const onLeave = () => { el.style.transform = ''; };
    el.addEventListener('mousemove', onMove);
    el.addEventListener('mouseleave', onLeave);
    return () => { el.removeEventListener('mousemove', onMove); el.removeEventListener('mouseleave', onLeave); };
  }, [strength]);
  return <span ref={ref} className={className} style={{ display:'inline-block', transition:'transform .35s cubic-bezier(.2,.7,.2,1)' }}>{children}</span>;
}

/* ─────────────  Reveal on scroll  ───────────── */

function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll('.rv');
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); }
      });
    }, { threshold: 0.12 });
    els.forEach(el => io.observe(el));
    return () => io.disconnect();
  }, []);
}

/* ─────────────  Grain (generated once)  ───────────── */

function makeGrainURL() {
  const c = document.createElement('canvas');
  c.width = c.height = 220;
  const ctx = c.getContext('2d');
  const img = ctx.createImageData(220, 220);
  for (let i=0; i<img.data.length; i+=4) {
    const v = (Math.random()*255)|0;
    img.data[i]=img.data[i+1]=img.data[i+2]=v;
    img.data[i+3] = (Math.random()*200)|0;
  }
  ctx.putImageData(img, 0, 0);
  return c.toDataURL('image/png');
}

/* ─────────────  Hero  ───────────── */

function Timecode() {
  const [tc, setTc] = useState('00:00:00:00');
  useEffect(() => {
    const start = performance.now();
    let raf;
    const tick = () => {
      const ms = performance.now() - start;
      const total = Math.floor(ms / 1000);
      const hh = String(Math.floor(total/3600)).padStart(2,'0');
      const mm = String(Math.floor(total/60)%60).padStart(2,'0');
      const ss = String(total%60).padStart(2,'0');
      const ff = String(Math.floor((ms%1000) / (1000/24))).padStart(2,'0');
      setTc(`${hh}:${mm}:${ss}:${ff}`);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);
  return <span className="tc">{tc}</span>;
}

function HeroAbout({ layout = 'simple' }) {
  if (layout === 'simple') {
    return (
      <section className="hero hero-simple" id="top">
        <div className="hsi-eyebrow rv">
          <span className="hsi-dot"></span>
          <span>Oussama Tarchouna — AI-native filmmaker</span>
        </div>

        <p className="hsi-lede rv">
          I make films with <span className="it">Generative AI</span> the way other directors make them with <span className="it">crews</span> — patiently, with a point of view, and never by accident.
        </p>

        <div className="hsi-body">
          <p className="rv d1">
            <strong>I'm Oussama</strong>, an AI-native filmmaker working between Tunis and Rotterdam. I direct AI videos, commercials, viral pieces, and short films; using the latest generation of video models<sup style={{fontFamily:'var(--mono)', fontSize:10}}>1</sup>.
          </p>
          <p className="rv d2">
            Before all of this, I was a brand designer. Logos, brand identities, websites — I've worked across the full spectrum.
          </p>
          <p className="rv d3">
            Moving into UX is what taught me to think like a viewer, not a maker. That perspective is what drives my approach to AI video: footage that doesn't feel AI, always in service of the brand <span className="it">(not the client)</span>.
          </p>
          <div className="footnote rv d4">
            <span className="label">— 1</span>
            <span>Yes, the same models you've seen ruin LinkedIn. Used carefully, they are a camera. Used carelessly, they are an embarrassment. I treat that distinction as a job.</span>
          </div>
        </div>
      </section>
    );
  }

  if (layout === 'split') {
    return (
      <section className="hero hero-split" id="top">
        <aside className="hs-side">
          <div className="hs-mark">
            <div className="hs-mark-row">
              <span className="hs-dot"></span>
              <span className="hs-mono">Portfolio — MMXXVI</span>
            </div>
            <h1 className="hs-name">
              <span className="word"><span>Oussama</span></span>
              <span className="word it"><span>Tarchouna</span></span>
            </h1>
            <div className="hs-role">
              <span>AI-native</span>
              <span className="it">filmmaker</span>
            </div>
          </div>

          <dl className="hs-facts">
            <div>
              <dt>Coordinates</dt>
              <dd>Tunis ↔ Rotterdam<br/><span className="hand">(mostly Tunis)</span></dd>
            </div>
          </dl>
        </aside>

        <div className="hs-main">
          <p className="hs-lede rv">
            I make films with <span className="it">Generative AI</span> the way other directors make them with <span className="it">crews</span> — patiently, with a point of view, and never by accident.
          </p>

          <div className="hs-body">
            <p className="rv d1">
              <strong>I'm Oussama</strong>, an AI-native filmmaker working between Tunis and Rotterdam. I direct AI videos, commercials, viral pieces, and short films; using the latest generation of video models<sup style={{fontFamily:'var(--mono)', fontSize:10}}>1</sup>.
            </p>
            <p className="rv d2">
              Before all of this, I was a brand designer. Logos, brand identities, websites — I've worked across the full spectrum.
            </p>
            <p className="rv d3">
              Moving into UX is what taught me to think like a viewer, not a maker. That perspective is what drives my approach to AI video: footage that doesn't feel AI, always in service of the brand <span className="it">(not the client)</span>.
            </p>
            <div className="footnote rv d4">
              <span className="label">— 1</span>
              <span>Yes, the same models you've seen ruin LinkedIn. Used carefully, they are a camera. Used carelessly, they are an embarrassment. I treat that distinction as a job.</span>
            </div>
          </div>
        </div>
      </section>
    );
  }

  // stacked (original)
  return (
    <section className="hero hero-about" id="top">
      <h1 className="hero-title">
        <span className="word w1"><span>O.Tarchouna</span></span>
      </h1>

      <div className="hero-tag">
        <div className="ln">AI-native filmmaker · Commercials, virals, short films</div>
      </div>

      <div className="about-grid hero-about-grid">
        <p className="about-lede rv">
          I make films with <span className="it">Generative AI</span> the way other directors make them with <span className="it">crews</span> — patiently, with a point of view, and never by accident.
        </p>

        <div className="about-body">
          <p className="rv d1">
            <strong>I'm Oussama</strong>, an AI-native filmmaker working between Tunis and Rotterdam. I direct AI videos, commercials, viral pieces, and short films; using the latest generation of video models<sup style={{fontFamily:'var(--mono)', fontSize:10}}>1</sup>.
          </p>
          <p className="rv d2">
            Before all of this, I was a brand designer. Logos, brand identities, websites — I've worked across the full spectrum.
          </p>
          <p className="rv d3">
            Moving into UX is what taught me to think like a viewer, not a maker. That perspective is what drives my approach to AI video: footage that doesn't feel AI, always in service of the brand <span className="it">(not the client)</span>.
          </p>
          <div className="footnote rv d4">
            <span className="label">— 1</span>
            <span>Yes, the same models you've seen ruin LinkedIn. Used carefully, they are a camera. Used carelessly, they are an embarrassment. I treat that distinction as a job.</span>
          </div>
        </div>
      </div>

      <div className="hero-meta">
        <div className="hero-meta-col">
          <div className="lbl">Coordinates</div>
          <div className="val">Tunis · Rotterdam · remote everywhere else</div>
          <div className="hand" style={{ marginTop:8, fontSize:18, opacity:.85, transform:'rotate(-1deg)' }}>(mostly Tunis, if I'm honest)</div>
        </div>
      </div>
    </section>
  );
}

/* ─────────────  Work rail  ───────────── */

function WorkRail({ motion }) {
  const wrap = useRef(null);
  const [pct, setPct] = useState(0);

  useEffect(() => {
    const el = wrap.current; if (!el) return;
    const onScroll = () => {
      const max = el.scrollWidth - el.clientWidth;
      setPct(max > 0 ? (el.scrollLeft / max) * 100 : 0);
    };
    el.addEventListener('scroll', onScroll, { passive:true });
    onScroll();
    return () => el.removeEventListener('scroll', onScroll);
  }, []);

  // wheel → horizontal
  useEffect(() => {
    const el = wrap.current; if (!el) return;
    const onWheel = (e) => {
      if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
        const max = el.scrollWidth - el.clientWidth;
        if (max <= 0) return;
        const next = el.scrollLeft + e.deltaY;
        if (next >= 0 && next <= max) {
          el.scrollLeft = next;
          e.preventDefault();
        }
      }
    };
    el.addEventListener('wheel', onWheel, { passive:false });
    return () => el.removeEventListener('wheel', onWheel);
  }, []);

  // keyboard
  useEffect(() => {
    const onKey = (e) => {
      if (!wrap.current) return;
      if (e.key === 'ArrowRight') wrap.current.scrollBy({ left: 600, behavior:'smooth' });
      if (e.key === 'ArrowLeft')  wrap.current.scrollBy({ left:-600, behavior:'smooth' });
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  return (
    <div className="work">
      <div className="work-rail-wrap" ref={wrap}>
        <div className="work-rail">
          {WORKS.map((w, i) => (
            <a className="work-card rv" data-cursor="play" href="#" key={w.num} onClick={e=>e.preventDefault()} style={{ transitionDelay: `${i*0.05}s` }}>
              <div className="thumb">
                <div className="thumb-inner video-cover">
                  <iframe
                    src={`https://www.youtube.com/embed/${w.yt}?playsinline=1`}
                    title={w.title}
                    frameBorder="0"
                    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
                    referrerPolicy="strict-origin-when-cross-origin"
                    allowFullScreen
                  />
                </div>
              </div>
              <div className="meta">
                <div className="left">
                  <div className="title">{w.title}</div>
                  <div className="sub">{w.sub}</div>
                </div>
              </div>
            </a>
          ))}

          {/* tail card — view all */}
          <a className="work-card rv" href="#contact" onClick={(e)=>{ e.preventDefault(); document.getElementById('contact')?.scrollIntoView({behavior:'smooth', block:'start'}); }}>
            <div className="thumb" style={{ display:'flex', alignItems:'center', justifyContent:'center', background:'transparent' }}>
              <div style={{ textAlign:'center' }}>
                <div className="serif" style={{ fontSize:48, lineHeight:1, marginBottom:14 }}>The rest <span style={{fontStyle:'italic', opacity:.7}}>on request</span></div>
                <div className="mono" style={{ fontSize:11, letterSpacing:'.18em', textTransform:'uppercase', color:'var(--ink-3)' }}>NDA reels available — get in touch →</div>
              </div>
            </div>
            <div className="meta">
              <div className="left">
                <div className="title">Full archive</div>
                <div className="sub">By request only</div>
              </div>
            </div>
          </a>
        </div>
      </div>
      <div className="work-progress"><span style={{ width: pct + '%' }}></span></div>
      <div className="work-hint">
        <span>Drag · scroll · or use arrows</span>
        <span className="keys"><span className="key">←</span><span className="key">→</span></span>
      </div>
    </div>
  );
}



/* ─────────────  Marquee  ───────────── */

function Marquee() {
  const items = [];
  for (let i=0; i<3; i++) {
    MARQUEE.forEach((w, j) => {
      items.push(
        <span key={`${i}-${j}`}>
          {w}<span className="star"> ✶ </span>
        </span>
      );
    });
  }
  return (
    <div className="marquee">
      <div className="marquee-track">{items}</div>
    </div>
  );
}

/* ─────────────  Contact  ───────────── */

function Contact() {
  const [form, setForm] = useState({ name:'', email:'', kind:'Commercial', msg:'' });
  const [sent, setSent] = useState(false);
  const [copied, setCopied] = useState(false);
  const submit = (e) => { e.preventDefault(); setSent(true); setTimeout(()=>setSent(false), 4000); };
  const copyEmail = () => {
    navigator.clipboard?.writeText('o@tarchouna.com');
    setCopied(true);
    setTimeout(()=>setCopied(false), 1800);
  };

  return (
    <section className="contact" id="contact">
      <div className="rv">
        <div className="eyebrow"><span className="dot"></span>03 · Contact</div>
      </div>
        <h2 className="contact-cta rv d1" style={{ marginTop:20, position:'relative' }}>
          <span className="scribble">try me</span>
          Let's make<br/>
          <span className="it">something</span> people<br/>
          actually <span className="it">finish</span> watching<span className="at">.</span>
        </h2>

      <div className="contact-grid">
        <form className="contact-form rv d1" onSubmit={submit}>
          <div className="row-2">
            <div className="field">
              <label>Your name</label>
              <input value={form.name} onChange={e=>setForm({...form, name:e.target.value})} placeholder="—" required />
            </div>
            <div className="field">
              <label>Email</label>
              <input type="email" value={form.email} onChange={e=>setForm({...form, email:e.target.value})} placeholder="—" required />
            </div>
          </div>
          <div className="field">
            <label>Project kind</label>
            <select value={form.kind} onChange={e=>setForm({...form, kind:e.target.value})}>
              <option>Commercial</option>
              <option>Viral / social</option>
              <option>Short film</option>
              <option>Music video</option>
              <option>Something else</option>
            </select>
          </div>
          <div className="field">
            <label>Tell me about it</label>
            <textarea value={form.msg} onChange={e=>setForm({...form, msg:e.target.value})} placeholder="Brief, deadline, what you're afraid of." required />
          </div>
          <button className="submit" type="submit" data-cursor="link">
            <span>{sent ? 'Sent — talk soon' : 'Send'} <span className="arr"></span></span>
          </button>
        </form>

        <div className="contact-side">
          <div className="contact-block rv d2">
            <div className="lbl">Email</div>
            <div className="v email-row">
              <a href="mailto:o@tarchouna.com" data-cursor="link">o@tarchouna.com</a>
              <button type="button" className="copy-btn" data-cursor="link" onClick={copyEmail} aria-label="Copy email">
                {copied ? 'Copied' : 'Copy'}
              </button>
            </div>
          </div>
          <div className="contact-block rv d3">
            <div className="lbl">Elsewhere</div>
            <div className="v">
              <a href="https://www.linkedin.com/in/tarchouna/" target="_blank" rel="noopener noreferrer" data-cursor="link">LinkedIn ↗</a>
            </div>
          </div>
          <div className="rv d4" style={{ marginTop:8 }}>
            <span className="signature">— Oussema</span>
            <div className="hand" style={{ fontSize:16, marginTop:4, opacity:.7 }}>(thank you for scrolling this far)</div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ─────────────  Clock  ───────────── */

function Clock() {
  const [t, setT] = useState('');
  useEffect(() => {
    const tick = () => {
      const d = new Date();
      const opt = { timeZone:'Africa/Tunis', hour:'2-digit', minute:'2-digit', second:'2-digit', hour12:false };
      setT(new Intl.DateTimeFormat('en-GB', opt).format(d) + ' TUN');
    };
    tick();
    const id = setInterval(tick, 1000);
    return () => clearInterval(id);
  }, []);
  return <span className="clock">{t}</span>;
}

/* ─────────────  Nav  ───────────── */

function Nav() {
  const [active, setActive] = useState('top');
  useEffect(() => {
    const ids = ['top','work','contact'];
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) setActive(e.target.id); });
    }, { rootMargin:'-30% 0px -60% 0px' });
    ids.forEach(id => { const el = document.getElementById(id); if (el) io.observe(el); });
    return () => io.disconnect();
  }, []);

  const go = (id) => (e) => {
    e.preventDefault();
    document.getElementById(id)?.scrollIntoView({ behavior:'smooth', block:'start' });
  };

  return (
    <nav className="nav">
      <a className="nav-logo" href="#top" onClick={go('top')}>O.<span><i>Tarchouna</i></span></a>
      <div className="nav-links">
        <a href="#top" data-cursor="link" className={active==='top'?'is-active':''} onClick={go('top')}><span className="num">01</span>Intro</a>
        <a href="#work" data-cursor="link" className={active==='work'?'is-active':''} onClick={go('work')}><span className="num">02</span>Videos</a>
        <a href="#contact" data-cursor="link" className={active==='contact'?'is-active':''} onClick={go('contact')}><span className="num">03</span>Contact</a>
      </div>
    </nav>
  );
}

/* ─────────────  App  ───────────── */

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  useReveal();

  // Inject grain dataURL once
  useEffect(() => {
    const url = makeGrainURL();
    document.documentElement.style.setProperty('--grain-url', `url("${url}")`);
  }, []);

  // Apply live tweaks
  useEffect(() => {
    document.documentElement.style.setProperty('--accent', t.accent);
    document.documentElement.style.setProperty('--grain', String(t.grain));
  }, [t.accent, t.grain]);

  return (
    <div className="page">
      <Cursor />
      <Nav />

      <HeroAbout layout={t.heroLayout} />

      <section className="sec" id="work">
        <div className="sec-head rv">
          <h2>AI Generated <span className="it">Videos</span></h2>
          <div className="tag">02 · Spec ads</div>
        </div>
        <WorkRail motion={t.motion} />
      </section>

      <Marquee />

      <Contact />

      <footer className="foot">
        <span>© O.Tarchouna · On a mission to make AI videos look less AI..</span>
        <span><Clock /></span>
      </footer>

      {/* overlays */}
      <div className="grain" style={{ display: t.grain > 0 ? 'block' : 'none' }} />
      {t.scanlines && <div className="scanline" />}
      <div className="vignette" />

      {/* Tweaks */}
      <TweaksPanel>
        <TweakSection label="Layout" />
        <TweakSelect label="Hero" value={t.heroLayout}
          options={[
            { value:'simple',  label:'Simple' },
            { value:'split',   label:'Editorial split' },
            { value:'stacked', label:'Stacked' }
          ]}
          onChange={v => setTweak('heroLayout', v)} />
        <TweakSection label="Look" />
        <TweakColor label="Accent" value={t.accent}
          options={['#f4f1ea','#d4ff3a','#ff6a3a','#5b8def','#c44']}
          onChange={v => setTweak('accent', v)} />
        <TweakSlider label="Grain" value={t.grain} min={0} max={0.2} step={0.01}
          onChange={v => setTweak('grain', v)} />
        <TweakToggle label="Scanlines" value={t.scanlines}
          onChange={v => setTweak('scanlines', v)} />
        <TweakSection label="Motion" />
        <TweakToggle label="Frame motion" value={t.motion}
          onChange={v => setTweak('motion', v)} />
      </TweaksPanel>
    </div>
  );
}

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