// Demo file shown on the simulated desktop and inside the Flik shelf.
// Matches what the real product shows for a HEIC photo: a thumbnail-style
// preview, a truncated filename, and inline "Convert to JPG" / "Remove"
// actions under the tile (per the heic_action screenshot).
const SOURCE_NAME = "IMG_4231.HEIC";
const CONVERTED_NAME = "IMG_4231.jpg";

function Hero() {
  const demoRef = React.useRef(null);
  const fileRef = React.useRef(null);
  const [pos, setPos] = React.useState({ x: 0.18, y: 0.55 }); // % of demo
  const [held, setHeld] = React.useState(false);
  const [shelfOpen, setShelfOpen] = React.useState(false);
  const [dropped, setDropped] = React.useState(false);
  const [activeAction, setActiveAction] = React.useState(null); // "convert" | "remove" | null
  const [converted, setConverted] = React.useState(false);
  const [removed, setRemoved] = React.useState(false);
  const [autoMode, setAutoMode] = React.useState(true);
  const [edgeNear, setEdgeNear] = React.useState(false);

  // ---- Auto-loop ----
  React.useEffect(() => {
    if (!autoMode) return;
    let cancelled = false;
    let timer;

    const seq = async () => {
      // reset
      setPos({ x: 0.18, y: 0.55 });
      setShelfOpen(false);
      setDropped(false);
      setActiveAction(null);
      setConverted(false);
      setRemoved(false);
      setEdgeNear(false);

      await wait(900);
      if (cancelled) return;
      // glide to right edge
      await tween((t) => setPos({ x: 0.18 + (0.78 - 0.18) * t, y: 0.55 - 0.05 * Math.sin(t * Math.PI) }), 1400);
      if (cancelled) return;
      setEdgeNear(true);
      await wait(280);
      if (cancelled) return;
      setShelfOpen(true);
      await wait(600);
      if (cancelled) return;
      // snap into shelf
      await tween((t) => setPos({ x: 0.78 + (0.86 - 0.78) * t, y: 0.55 - 0.05 + (0.28 - 0.50) * t }), 600);
      if (cancelled) return;
      setDropped(true);
      setEdgeNear(false);
      await wait(1100);
      if (cancelled) return;
      // press Convert to JPG
      setActiveAction("convert");
      await wait(700);
      if (cancelled) return;
      setConverted(true);
      setActiveAction(null);
      await wait(2400);
      if (cancelled) return;
      // close shelf
      setShelfOpen(false);
      await wait(700);
      if (cancelled) return;

      timer = setTimeout(seq, 200);
    };
    seq();

    return () => { cancelled = true; if (timer) clearTimeout(timer); };
  }, [autoMode]);

  // ---- Pointer interaction ----
  // Hover anywhere over the demo and the shelf reveals/hides based on the
  // cursor's X position — same gesture the real product uses (edge-trigger).
  // Threshold uses hysteresis: open at >0.78, close below 0.70, so the shelf
  // doesn't flicker right at the boundary.

  const onPointerEnter = () => {
    // Any cursor interaction takes the demo out of auto-mode. The Reset pill
    // in the hint bar puts it back.
    if (autoMode) setAutoMode(false);
  };

  const onPointerDown = (e) => {
    if (dropped) return;
    e.preventDefault();
    setAutoMode(false);
    setHeld(true);
    setDropped(false);
    setConverted(false);
    setRemoved(false);
    setActiveAction(null);
    e.currentTarget.setPointerCapture?.(e.pointerId);
  };

  const onPointerMove = (e) => {
    if (!demoRef.current) return;
    const rect = demoRef.current.getBoundingClientRect();
    const x = (e.clientX - rect.left) / rect.width;
    const y = (e.clientY - rect.top) / rect.height;
    const cx = clamp(x, 0.06, 0.96);
    const cy = clamp(y, 0.1, 0.92);

    // Drag the file token only when held.
    if (held) setPos({ x: cx, y: cy });

    // Edge-trigger logic — always on, hover or drag.
    if (autoMode) setAutoMode(false);
    setEdgeNear(cx > 0.70);
    if (cx > 0.78) setShelfOpen(true);
    else if (cx < 0.70) setShelfOpen(false);
  };

  const onPointerUp = () => {
    if (!held) return;
    setHeld(false);
    // If the cursor was inside the shelf zone, snap the file into the shelf;
    // otherwise just release. Shelf open/close state stays driven by pointer
    // position, NOT by whether we just dropped — so moving away still hides
    // the shelf even if a file is on it.
    if (pos.x > 0.78) {
      setPos({ x: 0.86, y: 0.28 });
      setDropped(true);
    }
    setEdgeNear(false);
  };

  // When the cursor leaves the demo entirely, treat it as "moved away from
  // the edge": close the shelf, release any drag in progress.
  const onPointerLeave = () => {
    if (held) {
      setHeld(false);
    }
    setEdgeNear(false);
    setShelfOpen(false);
  };

  const handleConvert = () => {
    if (converted || removed) return;
    setActiveAction("convert");
    setTimeout(() => {
      setConverted(true);
      setActiveAction(null);
    }, 450);
  };
  const handleRemove = () => {
    if (removed) return;
    setActiveAction("remove");
    setTimeout(() => setRemoved(true), 200);
  };

  const reset = () => {
    setHeld(false);
    setDropped(false);
    setConverted(false);
    setRemoved(false);
    setActiveAction(null);
    setEdgeNear(false);
    setShelfOpen(false);
    setPos({ x: 0.18, y: 0.55 });
    setAutoMode(true);
  };

  const currentName = converted ? CONVERTED_NAME : SOURCE_NAME;

  return (
    <section className="hero">
      <div className="container">
        <div className="hero-copy">
          <div className="hero-tag">
            <span className="dot"></span>
            <span>Coming soon · macOS 14+ · Apple Silicon &amp; Intel</span>
          </div>
          <h1>
            Your downloads,<br />
            <span style={{ color: "var(--accent)" }}>one cursor away.</span>
          </h1>
          <p className="lede" style={{ marginTop: 28 }}>
            A live, ephemeral shelf for everything you download. Push your cursor
            to the side of your screen — the shelf slides out, your file is
            already on it. Tidy by default. For Mac.
          </p>
          <div className="hero-cta">
            <span className="btn btn-soon" role="text" aria-disabled="true">
              <span className="soon-dot" aria-hidden="true"></span>
              Coming soon
            </span>
            <a className="btn btn-ghost" href="#how">
              See how it works
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
            </a>
          </div>
          <div className="hero-meta">
            <span>
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M8 12l3 3 5-6"/></svg>
              Native Swift &amp; SwiftUI
            </span>
            <span>
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M8 12l3 3 5-6"/></svg>
              Universal binary
            </span>
          </div>
        </div>

        <div
          className={"demo " + (edgeNear ? "near-edge " : "") + (held ? "dragging" : "")}
          ref={demoRef}
          onPointerEnter={onPointerEnter}
          onPointerMove={onPointerMove}
          onPointerUp={onPointerUp}
          onPointerLeave={onPointerLeave}
        >
          <DemoMenubar />
          <div className="demo-desktop">
            <div className="trigger-hint" />

            <div
              ref={fileRef}
              className={"demo-file " + (held ? "held" : "")}
              style={{
                left: `calc(${pos.x * 100}% - 48px)`,
                top: `calc(${pos.y * 100}% - 58px)`,
                opacity: dropped ? 0 : 1,
                pointerEvents: dropped ? "none" : "auto",
                transition: dropped ? "opacity 0.2s" : "none",
              }}
              onPointerDown={onPointerDown}
            >
              <div className="demo-file-thumb">
                <PhotoPreview />
              </div>
              <div className="demo-file-label">{SOURCE_NAME}</div>
            </div>

            <div className={"shelf " + (shelfOpen ? "open" : "")}>
              <div className="shelf-title">Flik</div>
              <div className={"shelf-dropzone " + (edgeNear && !dropped ? "over" : "")}>
                {dropped && !removed ? (
                  <div className={"shelf-tile selected " + (converted ? "converted " : "") + (activeAction === "remove" ? "removing" : "")}>
                    <div className="tile-thumb">
                      <PhotoPreview />
                      {converted && (
                        <div className="tile-converted-badge" aria-hidden="true">
                          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12l5 5L20 7"/></svg>
                        </div>
                      )}
                    </div>
                    <div className="tile-name" title={currentName}>{currentName}</div>
                    <div className="tile-actions">
                      {!converted && (
                        <button
                          type="button"
                          className={"tile-action primary " + (activeAction === "convert" ? "pressed" : "")}
                          onClick={handleConvert}
                        >
                          <ConvertIcon />
                          <span>Convert to JPG</span>
                        </button>
                      )}
                      <button
                        type="button"
                        className="tile-action secondary"
                        onClick={handleRemove}
                      >
                        Remove
                      </button>
                    </div>
                  </div>
                ) : (
                  <div className="shelf-empty">
                    <TrayIcon />
                    <div>Drop here</div>
                  </div>
                )}
              </div>
            </div>

            <div className="demo-hint">
              <span className="pulse"></span>
              {autoMode
                ? "Auto-demo · move your cursor near the right edge"
                : (dropped
                    ? (removed
                        ? "Removed — reset to try again"
                        : (converted ? "Converted" : "Try Convert to JPG"))
                    : (shelfOpen
                        ? "Drag the file in →"
                        : "Move your cursor to the right edge"))}
              {!autoMode && (
                <button onClick={reset} className="demo-hint-reset">Reset</button>
              )}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ----- Visual building blocks -----

// Stylized photo preview — sky gradient + faint hill + tree silhouette.
// Used both on the simulated desktop tile and in the Flik shelf tile, so the
// tile in the shelf is recognizably "the same image" the user dragged.
function PhotoPreview() {
  return (
    <svg viewBox="0 0 80 60" preserveAspectRatio="xMidYMid slice" width="100%" height="100%" aria-hidden="true">
      <defs>
        <linearGradient id="photo-sky" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0"  stopColor="#7da8c9" />
          <stop offset="0.7" stopColor="#cfdde9" />
          <stop offset="1"  stopColor="#e7ecef" />
        </linearGradient>
      </defs>
      <rect width="80" height="60" fill="url(#photo-sky)" />
      {/* clouds */}
      <ellipse cx="22" cy="14" rx="14" ry="3.2" fill="rgba(255,255,255,0.75)" />
      <ellipse cx="58" cy="20" rx="16" ry="3.5" fill="rgba(255,255,255,0.55)" />
      {/* distant hills */}
      <path d="M0 46 L18 38 L34 44 L50 36 L66 42 L80 38 L80 60 L0 60 Z" fill="#7c9874" opacity="0.85" />
      <path d="M0 50 L26 42 L42 48 L58 40 L74 46 L80 44 L80 60 L0 60 Z" fill="#4f6b48" />
      {/* tree silhouette */}
      <g transform="translate(28,28)">
        <rect x="3.5" y="14" width="2" height="10" fill="#2c3a26" />
        <path d="M4.5 0 L9 8 L7 8 L11 14 L7 14 L9 18 L0 18 L2 14 L-2 14 L2 8 L0 8 Z" fill="#2c3a26" />
      </g>
    </svg>
  );
}

// "Convert" icon — two opposing arrows in a swap pattern.
function ConvertIcon() {
  return (
    <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M4 8h13l-3-3" />
      <path d="M20 16H7l3 3" />
    </svg>
  );
}

function TrayIcon() {
  return (
    <svg width="34" height="34" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M22 12h-6l-2 3h-4l-2-3H2" />
      <path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" />
    </svg>
  );
}

function DemoMenubar() {
  const [time, setTime] = React.useState(formatTime(new Date()));
  React.useEffect(() => {
    const t = setInterval(() => setTime(formatTime(new Date())), 30_000);
    return () => clearInterval(t);
  }, []);
  return (
    <div className="demo-menubar">
      <div className="apple"></div>
      <span style={{ fontWeight: 600 }}>Finder</span>
      <span style={{ opacity: 0.85 }}>File</span>
      <span style={{ opacity: 0.85 }}>Edit</span>
      <span style={{ opacity: 0.85 }}>View</span>
      <span style={{ opacity: 0.85 }}>Go</span>
      <span style={{ opacity: 0.85 }}>Window</span>
      <span style={{ opacity: 0.85 }}>Help</span>
      <div className="mb-spacer"></div>
      <span className="mb-icon"><img src="assets/flik-icon.svg" alt="Flik" /></span>
      <span className="mb-time">{time}</span>
    </div>
  );
}

function formatTime(d) {
  const h = d.getHours();
  const m = d.getMinutes();
  const ampm = h >= 12 ? "PM" : "AM";
  const hh = ((h + 11) % 12) + 1;
  return `${hh}:${m.toString().padStart(2, "0")} ${ampm}`;
}

function clamp(n, lo, hi) { return Math.min(hi, Math.max(lo, n)); }
function wait(ms) { return new Promise(r => setTimeout(r, ms)); }
function tween(fn, dur) {
  return new Promise(resolve => {
    const start = performance.now();
    function frame(t) {
      const p = Math.min(1, (t - start) / dur);
      const eased = p < 0.5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2;
      fn(eased);
      if (p < 1) requestAnimationFrame(frame); else resolve();
    }
    requestAnimationFrame(frame);
  });
}

window.Hero = Hero;
