/* global React */
// ============================================================
// InfraMind — Animated mockups for the Platform page deepdives
// Four small components (Ingest → Detect → Rank → Decide),
// each rendered inside .dd-visual (4:3 aspect)
// ============================================================

const { useState: usePM, useEffect: useEffPM, useMemo: useMemoPM } = React;

// Shared looping clock — uses setInterval so it keeps running even when
// the tab is backgrounded (rAF gets throttled/paused). 30fps is plenty for these mockups.
function useLoopTime(duration = 8) {
  const [t, setT] = usePM(0);
  useEffPM(() => {
    const start = performance.now();
    const id = setInterval(() => {
      setT(((performance.now() - start) / 1000) % duration);
    }, 1000 / 30);
    return () => clearInterval(id);
  }, [duration]);
  return t;
}

const clampPM = (v, a = 0, b = 1) => Math.max(a, Math.min(b, v));

// ============================================================
// 01 — INGEST: multi-modal upload queue
// ============================================================
function IngestMockup() {
  const t = useLoopTime(9);

  const sources = [
    { name: "scan_north_seg04.las",    size: "4.2 GB",  tag: "LiDAR",   color: "#0EA5E9", start: 0.4 },
    { name: "uav_imagery_run03.zip",   size: "12.4 GB", tag: "Imagery", color: "#16A34A", start: 1.2 },
    { name: "visual_inspection.pdf",   size: "84 MB",   tag: "PDF",     color: "#525252", start: 2.0 },
    { name: "asset_register_a13.gpkg", size: "42 MB",   tag: "GIS",     color: "#525252", start: 2.8 },
  ];

  const totalDone = sources.filter(s => t > s.start + 1.4).length;
  const allDone = totalDone === sources.length;

  return (
    <div className="pm-frame">
      <div className="pm-head">
        <div className="pm-head-title">Ingest queue</div>
        <div className="pm-head-stat">
          <span className="pm-mono">{totalDone}/{sources.length}</span>
          <span className="pm-mono pm-dim">sources</span>
        </div>
      </div>

      <div className="pm-body pm-stack">
        {sources.map((s, i) => {
          const local = clampPM((t - s.start) / 1.4);
          const localStarted = t > s.start;
          const localDone = local >= 1;
          return (
            <div key={i} className="pm-file-row" style={{opacity: localStarted ? 1 : 0.35}}>
              <div className="pm-file-icon" style={{borderColor: s.color}}>
                <span style={{background: s.color}}></span>
              </div>
              <div className="pm-file-info">
                <div className="pm-file-name">{s.name}</div>
                <div className="pm-file-meta">
                  <span className="pm-mono pm-dim">{s.size}</span>
                  <span className="pm-tag" style={{color: s.color, borderColor: s.color}}>{s.tag}</span>
                </div>
              </div>
              <div className="pm-file-bar">
                <div className="pm-file-bar-fill" style={{width: `${local * 100}%`, background: s.color}}></div>
              </div>
              <div className="pm-file-status">
                {localDone ? <span className="pm-mono" style={{color: "var(--status-ok)"}}>✓</span> :
                 localStarted ? <span className="pm-mono pm-dim">{Math.floor(local * 100)}%</span> :
                 <span className="pm-mono pm-dim">queued</span>}
              </div>
            </div>
          );
        })}
      </div>

      <div className="pm-foot">
        <div className="pm-foot-row">
          <span className="pm-mono pm-dim">Co-registration</span>
          <span className="pm-pill" style={{
            background: allDone ? "rgba(22,163,74,0.1)" : "rgba(234,179,8,0.1)",
            color: allDone ? "var(--status-ok)" : "var(--sev-medium)",
          }}>{allDone ? "READY" : "WAITING"}</span>
        </div>
        <div className="pm-foot-row">
          <span className="pm-mono pm-dim">Total volume</span>
          <span className="pm-mono">16.7 GB</span>
        </div>
      </div>
    </div>
  );
}

// ============================================================
// 02a — UNIFY: every modality mapped onto one 3D model
// Mercury-style polished mockup — refined product chrome with
// real LiDAR scan imagery and floating data-source cards.
// ============================================================
function UnifyMockup() {
  const t = useLoopTime(11);

  // Each modality's "feed-in" card animates in sequentially
  const layers = [
    { id: "lidar", name: "LiDAR scan",         meta: "2.4M points",  appear: 0.4, swatch: "#0EA5E9" },
    { id: "img",   name: "Imagery",            meta: "47 plates",    appear: 2.0, swatch: "#16A34A" },
    { id: "rec",   name: "Inspection records", meta: "3 reports",    appear: 2.8, swatch: "#525252" },
  ];
  const opacityFor = (l) => clampPM((t - l.appear) * 2);
  const calloutP   = clampPM((t - 4.0) * 1.6);

  return (
    <div className="unify-stage">
      {/* Refined window chrome */}
      <div className="unify-window">
        <div className="unify-window-bar">
          <span className="unify-dot" style={{background: "#FF5F57"}}></span>
          <span className="unify-dot" style={{background: "#FEBC2E"}}></span>
          <span className="unify-dot" style={{background: "#28C840"}}></span>
          <span className="unify-window-crumb">
            <span className="pm-dim">app.inframind</span>
            <span className="pm-dim">/</span>
            <span>Demo Tunnel</span>
            <span className="pm-dim">/</span>
            <span>3D View</span>
          </span>
        </div>

        {/* Scan area — real product screenshot */}
        <div className="unify-canvas">
          <img
            src="assets/scan-3d.png"
            alt="LiDAR scan of Demo Tunnel showing classified defects on the 3D digital twin"
            className="unify-scan"
          />
          {/* Subtle gradient softens the embedded UI edges */}
          <div className="unify-canvas-fade"></div>

          {/* Floating defect callout — rich, evidence-anchored */}
          <div
            className="unify-callout"
            style={{
              opacity: calloutP,
              transform: `translateY(${(1 - calloutP) * 8}px)`,
            }}
          >
            <div className="unify-callout-head">
              <span className="unify-callout-id">CR-04</span>
              <span className="unify-callout-sev">CRITICAL</span>
            </div>
            <div className="unify-callout-title">Longitudinal crack · crown · ch&nbsp;412.6&nbsp;m</div>
            <div className="unify-callout-evidence">
              {[
                { k: "LIDAR",  v: "12.8 mm",   note: "crack width" },
                { k: "IMG",    v: "plate 042", note: "visual confirmation" },
                { k: "RECORD", v: "2019",      note: "earliest mention" },
              ].map(e => (
                <div className="unify-evidence-row" key={e.k}>
                  <span className="unify-evidence-k">{e.k}</span>
                  <span className="unify-evidence-v">{e.v}</span>
                  <span className="unify-evidence-note">{e.note}</span>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>

      {/* Floating data-source cards on the left, feeding into the asset model */}
      <div className="unify-sources">
        <div className="unify-sources-lbl pm-mono">DATA FEEDING IN</div>
        {layers.map((l) => {
          const op = opacityFor(l);
          return (
            <div
              key={l.id}
              className="unify-source-card"
              style={{
                opacity: op,
                transform: `translateX(${(1 - op) * -12}px)`,
              }}
            >
              <span className="unify-source-swatch" style={{background: l.swatch}}></span>
              <span className="unify-source-name">{l.name}</span>
              <span className="unify-source-meta pm-mono">{l.meta}</span>
              <span className="unify-source-check">
                {op >= 1 ? (
                  <svg width="11" height="11" viewBox="0 0 11 11" fill="none">
                    <path d="M2 5.5L4.5 8L9 3" stroke="#16A34A" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/>
                  </svg>
                ) : null}
              </span>
            </div>
          );
        })}
        <div className="unify-sources-foot pm-mono pm-dim">
          → co-registered onto one asset model
        </div>
      </div>
    </div>
  );
}

// ============================================================
// 03 — DETECT: AI scanning a tunnel surface
// ============================================================
function DetectMockup() {
  // Real product capture of AI defect detection on the tunnel wall —
  // each affected element segmented, classified, and quantified.
  return (
    <div className="pm-frame">
      <div className="pm-head">
        <div className="pm-head-title">AI defect detection</div>
        <div className="pm-head-stat">
          <span className="pm-mono pm-dim">chainage</span>
          <span className="pm-mono">7.86 m</span>
        </div>
      </div>

      <div className="pm-body" style={{padding: 0, position: "relative", background: "#FAFAFA"}}>
        <img
          src="assets/defect-detail.png"
          alt="Tunnel lining close-up with AI-detected spalling on each affected brick, with per-defect dimensions"
          style={{
            position: "absolute",
            inset: 0,
            width: "100%",
            height: "100%",
            objectFit: "cover",
            objectPosition: "center",
            display: "block",
            filter: "saturate(1) contrast(1.02)",
          }}
        />

        {/* Floating quantification badge — anchored to the bottom-right corner */}
        <div className="pm-detect-quant">
          <div className="pm-mono pm-dim" style={{fontSize: 10}}>Spalling · brick 04 / 06</div>
          <div className="pm-detect-quant-grid">
            <div>
              <div className="pm-detect-quant-k">Depth</div>
              <div className="pm-detect-quant-v">163 mm</div>
            </div>
            <div>
              <div className="pm-detect-quant-k">Area</div>
              <div className="pm-detect-quant-v">8.36×10⁶ mm²</div>
            </div>
            <div>
              <div className="pm-detect-quant-k">Volume</div>
              <div className="pm-detect-quant-v">1.36×10⁹ mm³</div>
            </div>
          </div>
        </div>
      </div>

      <div className="pm-foot">
        <div className="pm-foot-row">
          <span className="pm-mono pm-dim">Models</span>
          <span className="pm-mono">CV · LiDAR</span>
        </div>
        <div className="pm-foot-row">
          <span className="pm-mono pm-dim">Avg confidence</span>
          <span className="pm-mono" style={{color: "var(--status-ok)"}}>0.94</span>
        </div>
      </div>
    </div>
  );
}

// ============================================================
// 03 — RANK: defects sorted with FLIP-style animation
// ============================================================
function RankMockup() {
  const t = useLoopTime(8);

  // Initial random-ish order
  const initialOrder = [
    { id: "DF-02",   type: "Deformation",      loc: "ch 416", val: "1.6 mm",  score: 34, sev: "low",  color: "var(--ink-500)" },
    { id: "CR-04",   type: "Longitudinal crack", loc: "ch 412.6", val: "12.8 mm", score: 87, sev: "crit", color: "var(--sev-critical)" },
    { id: "CR-07",   type: "Transverse crack",  loc: "ch 420",   val: "5.2 mm",  score: 58, sev: "med",  color: "var(--sev-medium)" },
    { id: "CR-02",   type: "Longitudinal crack", loc: "ch 418.2", val: "9.6 mm",  score: 82, sev: "crit", color: "var(--sev-critical)" },
    { id: "SP-12",   type: "Concrete spalling", loc: "ch 414.0", val: "4.2 mm",  score: 64, sev: "high", color: "var(--sev-high)" },
    { id: "CR-09",   type: "Surface crack",    loc: "ch 419.5", val: "3.1 mm",  score: 41, sev: "med",  color: "var(--sev-medium)" },
  ];

  // Target sorted order: descending by score
  const sortedOrder = [...initialOrder].sort((a, b) => b.score - a.score);
  const targetIndex = initialOrder.map(item => sortedOrder.findIndex(x => x.id === item.id));

  // Animation: 0-1s reveal, 1-3s "scoring", 3-4s sort, 4-7s hold, 7-8s reset
  const reveal = clampPM(t / 0.8);
  const scoring = clampPM((t - 1.0) / 1.8);
  const sortP = t < 3 ? 0 : t < 4 ? clampPM((t - 3) / 1.0) : t < 7 ? 1 : clampPM((8 - t) / 1.0);

  const rowH = 36;
  const rowGap = 4;

  return (
    <div className="pm-frame">
      <div className="pm-head">
        <div className="pm-head-title">Risk-ranked defects</div>
        <div className="pm-head-stat">
          <span className="pm-mono pm-dim">sorted by</span>
          <span className="pm-mono">composite score</span>
        </div>
      </div>

      <div className="pm-body" style={{padding: "12px 16px", position: "relative"}}>
        {/* Column header */}
        <div className="pm-rank-head pm-mono pm-dim">
          <span>SEV</span><span>DEFECT</span><span>LOC</span><span>VALUE</span><span>SCORE</span>
        </div>
        {/* Rows */}
        <div className="pm-rank-rows" style={{position: "relative", height: initialOrder.length * (rowH + rowGap)}}>
          {initialOrder.map((row, originalIdx) => {
            const targetIdx = targetIndex[originalIdx];
            const currentIdx = originalIdx + (targetIdx - originalIdx) * sortP;
            const top = currentIdx * (rowH + rowGap);
            const itemReveal = clampPM((t - originalIdx * 0.08) / 0.4);
            return (
              <div key={row.id} className="pm-rank-row" style={{
                top, opacity: itemReveal,
                transform: `translateY(${(1 - itemReveal) * 10}px)`,
              }}>
                <span className="pm-rank-sev">
                  <i style={{background: row.color}}></i>
                </span>
                <span className="pm-rank-defect">
                  <span className="pm-rank-id pm-mono">{row.id}</span>
                  <span className="pm-rank-type">{row.type}</span>
                </span>
                <span className="pm-mono pm-dim">{row.loc}</span>
                <span className="pm-mono">{row.val}</span>
                <span className="pm-rank-score">
                  <span className="pm-rank-bar">
                    <span className="pm-rank-bar-fill" style={{width: `${row.score * scoring}%`, background: row.color}}></span>
                  </span>
                  <span className="pm-mono pm-rank-num">{Math.floor(row.score * scoring)}</span>
                </span>
              </div>
            );
          })}
        </div>
      </div>

      <div className="pm-foot">
        <div className="pm-foot-row">
          <span className="pm-mono pm-dim">Inputs</span>
          <span className="pm-mono">severity × confidence × Δ history</span>
        </div>
      </div>
    </div>
  );
}

// ============================================================
// 04 — DECIDE: engineer review queue + export
// ============================================================
function DecideMockup() {
  const t = useLoopTime(10);

  // Rows reveal early (t=0-1), then actions resolve sequentially
  const items = [
    { id: "CR-04",   defect: "Longitudinal crack",  reviewer: "JC", action: "approved", color: "var(--status-ok)",   reveal: 0.0, resolve: 1.6 },
    { id: "CR-02",   defect: "Transverse crack",    reviewer: "JC", action: "approved", color: "var(--status-ok)",   reveal: 0.15, resolve: 2.4 },
    { id: "SP-12",   defect: "Concrete spalling",   reviewer: "MA", action: "edited",   color: "var(--sev-medium)",  reveal: 0.30, resolve: 3.2, edit: "S3 → S2" },
    { id: "CR-07",   defect: "Shear crack",         reviewer: "RN", action: "queried",  color: "var(--status-info)", reveal: 0.45, resolve: 4.0, note: "re-scan requested" },
    { id: "DF-02",   defect: "Deformation",         reviewer: "JC", action: "approved", color: "var(--status-ok)",   reveal: 0.60, resolve: 4.8 },
  ];

  const exportPressed = t > 5.6 && t < 6.2;
  const exportDone = t > 6.2;

  return (
    <div className="pm-frame">
      <div className="pm-head">
        <div className="pm-head-title">Engineer review</div>
        <div className="pm-head-stat" style={{gap: 0}}>
          {["JC", "MA", "RN", "SP"].map((a, i) => (
            <span key={i} className="pm-avatar">{a}</span>
          ))}
        </div>
      </div>

      <div className="pm-body pm-stack" style={{padding: "10px 16px", gap: 6}}>
        {items.map((it) => {
          const visible = clampPM((t - it.reveal) / 0.35);
          const resolved = t > it.resolve;
          return (
            <div key={it.id} className="pm-decide-row" style={{opacity: visible, transform: `translateX(${(1 - visible) * 10}px)`}}>
              <span className="pm-decide-id pm-mono">{it.id}</span>
              <span className="pm-decide-defect">{it.defect}</span>
              {resolved ? (
                <span className="pm-decide-action" style={{color: it.color, borderColor: it.color, background: "rgba(255,255,255,0.6)"}}>
                  <span className="pm-avatar small" style={{background: "var(--ink-100)", color: "var(--ink-1000)", border: "1px solid var(--ink-200)"}}>{it.reviewer}</span>
                  {it.action}{it.edit ? ` · ${it.edit}` : ""}
                </span>
              ) : (
                <span className="pm-decide-action" style={{color: "var(--ink-500)", borderColor: "var(--ink-200)"}}>
                  pending review
                </span>
              )}
            </div>
          );
        })}
      </div>

      <div className="pm-foot">
        <div className="pm-foot-row" style={{justifyContent: "space-between"}}>
          <span className="pm-mono pm-dim">Audit log · 412 events</span>
          <button className={`pm-export-btn ${exportPressed ? "pressed" : ""}`} style={exportDone ? {background: "var(--status-ok)"} : null}>
            {exportDone ? "✓ Evidence pack ready" : "↓ Export evidence pack"}
          </button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, {
  IngestMockup, UnifyMockup, DetectMockup, RankMockup, DecideMockup,
});
