/* global React, ReactDOM */
const { useState, useEffect, useRef, useCallback } = React;

// ---------- tile layout pattern (cinematic rhythm) ----------
// 1 wide feature, then pairs + triples, repeating
const SPAN_PATTERN = ["two-thirds", "third", "half", "half", "third", "third", "third", "wide"];

function spanFor(i) {
  return SPAN_PATTERN[i % SPAN_PATTERN.length];
}

// ---------- load prefetched live video list (synced from Vimeo) ----------
async function loadVideos() {
  try {
    const r = await fetch('videos.json');
    if (!r.ok) throw new Error('videos.json ' + r.status);
    const d = await r.json();
    return (d.videos || []).map((v) => ({
      id: v.id,
      title: v.title,
      thumb: v.thumb || `https://vumbnail.com/${v.id}_large.jpg`,
      duration: v.duration || 0,
      uploadDate: v.created || "",
      ok: true
    }));
  } catch (e) {
    console.error('videos.json load failed', e);
    return [];
  }
}

function formatDuration(s) {
  if (!s) return "";
  const m = Math.floor(s / 60),ss = s % 60;
  return `${m}:${String(ss).padStart(2, "0")}`;
}
function year(date) {
  if (!date) return "";
  return date.slice(0, 4);
}

// ---------- Hero ----------
function Hero({ config, videos }) {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 40);
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  // hero: the most recent upload, looping as background
  const currentId = videos[0]?.id;
  const src = currentId && config.heroAutoplay ?
  `https://player.vimeo.com/video/${currentId}?background=1&autoplay=1&loop=1&byline=0&title=0&muted=1&controls=0&quality=1080p` :
  null;

  return (
    <header className="hero" data-screen-label="Hero">
      <div className="hero-video">
        {src ?
        <iframe
          key={currentId}
          src={src}
          title=""
          allow="autoplay; fullscreen"
          frameBorder="0" /> :


        <div className="hero-fallback" />
        }
      </div>
      <div className="hero-vignette" />
      {config.showLetterbox && <>
        <div className="letterbox top" />
        <div className="letterbox bottom" />
      </>}

      <div className="hero-content">
        <h1 className="hero-title">
          {config.name.split(" ").map((w, i, arr) =>
          <React.Fragment key={i}>
              {i === arr.length - 1 ? <em>{w}</em> : w}
              {i < arr.length - 1 ? " " : ""}
            </React.Fragment>
          )}
        </h1>
        <div className="hero-meta">
          <div>
            <div className="hero-meta-label">Role</div>
            <div className="hero-meta-value">{config.role}</div>
          </div>
          <div>
            <div className="hero-meta-label">L</div>
            <div className="hero-meta-value">{"\n"}</div>
          </div>
        </div>
      </div>

      <div className="hero-scroll">Scroll</div>
    </header>);

}

// ---------- Nav ----------
function Nav({ config, route, go }) {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 100);
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  const link = (to, label) =>
  <a href={`#/${to}`} className={route === to ? "active" : ""} onClick={(e) => {e.preventDefault();go(to);}}>{label}</a>;

  return (
    <nav className={`nav ${scrolled || route !== "work" ? "scrolled" : ""}`}>
      <a href="#/work" className="nav-mark" onClick={(e) => {e.preventDefault();go("work");}}>
        {config.name}<em></em>
      </a>
      <div className="nav-links">
        {link("work", "Work")}
        {link("about", "About")}
        {link("contact", "Contact")}
      </div>
    </nav>);

}

// ---------- Tile ----------
function Tile({ video, index, span, onOpen }) {
  const [hover, setHover] = useState(false);
  const [iframeLoaded, setIframeLoaded] = useState(false);
  const hoverTimer = useRef(null);

  const onEnter = () => {
    hoverTimer.current = setTimeout(() => setHover(true), 280);
  };
  const onLeave = () => {
    clearTimeout(hoverTimer.current);
    setHover(false);
    setIframeLoaded(false);
  };

  return (
    <div
      className={`tile ${span}`}
      onMouseEnter={onEnter}
      onMouseLeave={onLeave}
      onClick={() => onOpen(video)}>
      
      <div className="tile-media">
        {!video.ok && <div className="tile-loading">Loading</div>}
        {video.thumb && <img src={video.thumb} alt="" loading="lazy" />}
        {hover && video.ok &&
        <div className={`iframe-wrap ${iframeLoaded ? "playing" : ""}`}>
            <iframe
            src={`https://player.vimeo.com/video/${video.id}?background=1&autoplay=1&loop=1&muted=1&byline=0&title=0&controls=0`}
            allow="autoplay"
            frameBorder="0"
            onLoad={() => setIframeLoaded(true)} />
          
          </div>
        }
      </div>
      <div className="tile-shade" />
      <div className="tile-index">№ {String(index + 1).padStart(2, "0")}</div>
      <div className="tile-play">
        <svg viewBox="0 0 10 10"><polygon points="1,0 9,5 1,10" /></svg>
      </div>
      <div className="tile-info">
        <div>
          <div className="tile-title">{video.title || "Untitled"}</div>

        </div>
      </div>
    </div>);

}

// ---------- Lightbox ----------
function Lightbox({ video, onClose }) {
  useEffect(() => {
    const k = (e) => {if (e.key === "Escape") onClose();};
    window.addEventListener("keydown", k);
    return () => window.removeEventListener("keydown", k);
  }, [onClose]);

  return (
    <div className={`lightbox ${video ? "open" : ""}`} onClick={onClose}>
      <div className="lightbox-inner" onClick={(e) => e.stopPropagation()}>
        <button className="lightbox-close" onClick={onClose}>
          <span>Close</span>
          <svg width="12" height="12" viewBox="0 0 12 12"><path d="M1 1l10 10M11 1L1 11" stroke="currentColor" strokeWidth="1" fill="none" /></svg>
        </button>
        {video &&
        <>
            <iframe
            src={`https://player.vimeo.com/video/${video.id}?autoplay=1&byline=0&title=0&portrait=0&badge=0`}
            allow="autoplay; fullscreen; picture-in-picture"
            allowFullScreen
            frameBorder="0" />
          
            <div className="lightbox-caption">
              <h3>{video.title}</h3>
              <span>{[year(video.uploadDate), formatDuration(video.duration)].filter(Boolean).join(" · ")}</span>
            </div>
          </>
        }
      </div>
    </div>);

}

// ---------- Work Section ----------
function Work({ videos, onOpen, id, label, numLabel, count }) {
  const slice = videos.slice(0, count || videos.length);
  return (
    <section id={id} data-screen-label={label}>
      <div className="section-header">
        <div className="section-num">{numLabel}</div>
        <div className="section-rule" />
        <h2 className="section-title">{label}</h2>
      </div>
      <div className="work-grid">
        {slice.map((v, i) =>
        <Tile key={v.id} video={v} index={i} span={spanFor(i)} onOpen={onOpen} />
        )}
      </div>
    </section>);

}

// ---------- About page ----------
function PageAbout({ config }) {
  return (
    <main className="page page-about">
      <section className="about" data-screen-label="About">
        <div>
          <div className="about-label">— About Me</div>
          <div>
            <h4 style={{ fontFamily: "var(--display)", lineHeight: 1, letterSpacing: "-0.035em", textTransform: "uppercase", fontWeight: 500, fontSize: 48 }}>Don't sell. Make people feel.</h4>
          </div>
        </div>
        <div>
          <div className="about-body" style={{ fontFamily: "Helvetica, sans-serif", fontWeight: 300, letterSpacing: "-0.005em" }}>
            <p>I'm Said Kassed, a director and cinematographer based in Casablanca, Morocco.</p>
            <p>I work in commercial films, music videos, and TVCs. My approach is simple: don't sell, make people feel. Every frame has a reason. Every cut has intention.</p>
            <p>Over the years I've worked across Morocco, Dubai, Abu Dhabi, Istanbul, New York, and beyond. I bring the same energy to every project. Cinematic, story-driven, and built to last.</p>
            <p>I believe great work comes from trust. Between director and client. Between vision and execution. I don't just show up to shoot. I come with ideas, with references, with a point of view.</p>

            <h5 className="about-subhead" style={{ fontWeight: "700", fontFamily: "\"Helvetica Neue\"", letterSpacing: "-0.7px" }}>Let's Work Together</h5>
            <p>I'm open to collaborations on commercial projects, music videos, branded content, and TVCs, locally and internationally.</p>
            <p>If you have a project coming up and you're looking for a director or DP who's serious about the craft, let's talk.</p>
            <p>I work as a freelancer, which means I move fast, I adapt, and I bring full focus to every project I take on. No agency layers. Direct communication. Clean results.</p>
            <p>Reach out and let's build something worth watching.</p>
          </div>
        </div>
      </section>
    </main>);

}

// ---------- Contact page ----------
function PageContact({ config }) {
  const [copied, setCopied] = useState(null);

  const copy = async (text, key) => {
    try {
      await navigator.clipboard.writeText(text);
      setCopied(key);
      setTimeout(() => setCopied((c) => c === key ? null : c), 1600);
    } catch (e) {}
  };

  return (
    <main className="page page-contact">
      <section id="contact" className="contact contact-split" data-screen-label="Contact">
        <div className="contact-left">
          <div className="contact-eyebrow">— Let's work together</div>
          <h2 className="contact-heading">Let's build<br />something<br />worth watching.</h2>
          <div className="contact-blurb">
            <p>Open to collaborations on commercial projects, music videos, branded content, and TVCs — locally and internationally.</p>
            <p>I work as a freelancer. I move fast, I adapt, and I bring full focus to every project I take on. No agency layers. Direct communication. Clean results.</p>
          </div>
          <div className="contact-socials contact-socials-inline">
            <a href={`https://instagram.com/${config.instagram}`} target="_blank" rel="noopener">Instagram</a>
            <span style={{ color: "var(--ink-mute)" }}>·</span>
            <a href={`https://vimeo.com/${config.vimeoUser}`} target="_blank" rel="noopener">Portfolio</a>
          </div>
        </div>

        <div className="contact-right">
          <div className="bizcard-stage">
            <div className="bizcard-label">— Card</div>
            <article className="bizcard" aria-label="Contact card for Said Kassed">
              <div className="bizcard-corner bizcard-corner-tl" aria-hidden="true"></div>
              <div className="bizcard-corner bizcard-corner-tr" aria-hidden="true"></div>
              <div className="bizcard-corner bizcard-corner-bl" aria-hidden="true"></div>
              <div className="bizcard-corner bizcard-corner-br" aria-hidden="true"></div>

              <div className="bizcard-head">
                <div className="bizcard-mark">
                  <span className="bizcard-mark-dot" style={{ background: "var(--accent)" }} />
                  <span className="bizcard-mark-txt">SK · Est. 2018</span>
                </div>
                <div className="bizcard-meta">No. 001</div>
              </div>

              <div className="bizcard-body">
                <div className="bizcard-name">Said Kassed</div>
                <div className="bizcard-role">
                  <span>Director</span>
                  <span className="bizcard-sep" aria-hidden="true"></span>
                  <span>Cinematographer</span>
                </div>
              </div>

              <div className="bizcard-foot">
                <button
                  type="button"
                  className="bizcard-contact"
                  onClick={() => copy(config.email, "email")}
                  title="Click to copy"
                >
                  <span className="bizcard-contact-label">Email</span>
                  <span className="bizcard-contact-value">{config.email}</span>
                  <span className={`bizcard-copied ${copied === "email" ? "is-on" : ""}`}>Copied</span>
                </button>
              </div>
            </article>
            <div className="bizcard-hint">Tap email to copy</div>
          </div>
        </div>
      </section>
    </main>);

}

// ---------- Footer ----------
function Footer({ config }) {
  return (
    <footer className="footer">
      <div><span className="footer-dot" />Available for select projects</div>
      <div>© {new Date().getFullYear()} {config.name}. All films property of their respective clients.</div>
      <div>Site last synced · {new Date().toLocaleDateString("en-US", { day: "2-digit", month: "short", year: "numeric" })}</div>
    </footer>);

}

// ---------- Tweaks (edit-mode) ----------
function Tweaks({ config, setConfig }) {
  const [open, setOpen] = useState(false);

  useEffect(() => {
    const onMsg = (e) => {
      if (!e.data || !e.data.type) return;
      if (e.data.type === "__activate_edit_mode") setOpen(true);
      if (e.data.type === "__deactivate_edit_mode") setOpen(false);
    };
    window.addEventListener("message", onMsg);
    window.parent.postMessage({ type: "__edit_mode_available" }, "*");
    return () => window.removeEventListener("message", onMsg);
  }, []);

  const setKey = (k, v) => {
    setConfig((c) => ({ ...c, [k]: v }));
    window.parent.postMessage({ type: "__edit_mode_set_keys", edits: { [k]: v } }, "*");
  };

  const accents = [
  { name: "amber", hex: "#c89b6e" },
  { name: "red", hex: "#a03838" },
  { name: "blue", hex: "#5a8bb0" },
  { name: "cream", hex: "#e8dcc4" },
  { name: "pure", hex: "#f4f0e8" }];


  return (
    <div className={`tweaks ${open ? "open" : ""}`}>
      <h5>Tweaks</h5>
      <div className="tweaks-row">
        <label>Accent</label>
        <div className="swatches">
          {accents.map((a) =>
          <button
            key={a.name}
            className="swatch"
            style={{ background: a.hex, outline: config.accent === a.hex ? "1px solid #fff" : "none", outlineOffset: 2 }}
            onClick={() => {setKey("accent", a.hex);setKey("accentName", a.name);}}
            title={a.name} />

          )}
        </div>
      </div>
      <div className="tweaks-row">
        <label>Film grain</label>
        <input type="checkbox" checked={config.showGrain} onChange={(e) => setKey("showGrain", e.target.checked)} />
      </div>
      <div className="tweaks-row">
        <label>Hero autoplay</label>
        <input type="checkbox" checked={config.heroAutoplay} onChange={(e) => setKey("heroAutoplay", e.target.checked)} />
      </div>
      <div className="tweaks-row">
        <label>Letterbox bars</label>
        <input type="checkbox" checked={config.showLetterbox} onChange={(e) => setKey("showLetterbox", e.target.checked)} />
      </div>
    </div>);

}

// ---------- App ----------
function App() {
  const [config, setConfig] = useState(window.SITE_CONFIG);
  const [videos, setVideos] = useState([]);
  const [open, setOpen] = useState(null);
  const [route, setRoute] = useState(() => location.hash.replace("#/", "") || "work");

  // hash router
  useEffect(() => {
    const onHash = () => {
      const r = location.hash.replace("#/", "") || "work";
      setRoute(["work", "about", "contact"].includes(r) ? r : "work");
      window.scrollTo({ top: 0, behavior: "instant" });
    };
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);
  const go = (r) => {location.hash = "#/" + r;};

  // propagate accent to CSS var
  useEffect(() => {
    document.documentElement.style.setProperty("--accent", config.accent);
  }, [config.accent]);

  // load live-synced videos.json (generated by the Vercel/Netlify cron)
  useEffect(() => {
    let cancelled = false;
    (async () => {
      const list = await loadVideos();
      if (!cancelled) setVideos(list);
    })();
    return () => {cancelled = true;};
  }, []);

  // reveal on scroll
  useEffect(() => {
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {if (e.isIntersecting) e.target.classList.add("in");});
    }, { threshold: 0.1 });
    document.querySelectorAll(".reveal").forEach((el) => io.observe(el));
    return () => io.disconnect();
  }, [videos]);

  return (
    <>
      {config.showGrain && <div className="grain" />}
      <Nav config={config} route={route} go={go} />

      {route === "work" &&
      <>
          <Hero config={config} videos={videos} />
          <Work
          id="work"
          label="Selected Work"
          numLabel="01 / Reel"
          videos={videos}
          onOpen={setOpen} />
        </>
      }

      {route === "about" && <PageAbout config={config} />}
      {route === "contact" && <PageContact config={config} />}

      <Footer config={config} />

      <Lightbox video={open} onClose={() => setOpen(null)} />
      <Tweaks config={config} setConfig={setConfig} />
    </>);

}

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