// Shared UI components
const { useState, useEffect, useMemo, useRef } = React;

// ---------- Portrait placeholder (fake deer photo) ----------
function Portrait({ palette, id, label, aspect = "4 / 5", style = {}, photo, photoTone }) {
  const [c1, c2, c3] = palette || ["#3a2a1f", "#7a5a3e", "#c19876"];
  const bgStyle = photo
    ? {
        backgroundImage: `url(${photo})`,
        backgroundSize: "cover",
        backgroundPosition: "center",
        filter: photoTone || undefined,
      }
    : {};
  return (
    <div
      className="deer-portrait"
      style={{ aspectRatio: aspect, "--c1": c1, "--c2": c2, "--c3": c3, ...bgStyle, ...style }}
    >
      {id && <div className="deer-portrait-id">● {id}</div>}
      {label && <div className="deer-portrait-label">{label}</div>}
    </div>
  );
}

// ---------- Observation media preview ----------
function normalizeMediaType(media = {}) {
  if (media.type) return media.type;
  if (media.mime && media.mime.startsWith("video/")) return "video";
  if (/\.(mp4|webm|mov|m4v)(\?|#|$)/i.test(media.url || "")) return "video";
  return "image";
}

function getSightingMedia(sighting = {}, animal = null) {
  const items = [];
  if (Array.isArray(sighting.media)) {
    sighting.media.forEach((m, i) => {
      if (m && m.url) items.push({
        id: m.id || `${sighting.id || "OBS"}-M${i + 1}`,
        type: normalizeMediaType(m),
        url: m.url,
        role: m.role || (i === 0 ? "识别主图" : "补充素材"),
        title: m.title || m.name || "",
        note: m.note || "",
        recognition: m.recognition !== false && i === 0,
      });
    });
  }
  if (!items.length && sighting.photo) {
    items.push({
      id: `${sighting.id || "OBS"}-PHOTO`,
      type: normalizeMediaType({ url: sighting.photo, mime: sighting.photoMime }),
      url: sighting.photo,
      role: "识别主图",
      title: "观察上传图",
      recognition: true,
    });
  }
  if (!items.length && animal?.photo) {
    items.push({
      id: `${sighting.id || "OBS"}-ANIMAL`,
      type: "image",
      url: animal.photo,
      role: "关联档案主图",
      title: animal.name,
      recognition: false,
      fallback: true,
    });
  }
  return items;
}

function MediaPreview({ media, tone, label, aspect = "4 / 5", compact = false }) {
  const type = normalizeMediaType(media || {});
  const role = media?.role || (type === "video" ? "补充视频" : "补充图片");
  return (
    <div style={{ aspectRatio: aspect, border: "1px solid var(--rule)", background: "var(--paper-2)", position: "relative", overflow: "hidden" }}>
      {media?.url ? (
        type === "video" ? (
          <video src={media.url} controls muted playsInline style={{ width: "100%", height: "100%", objectFit: "cover", display: "block", background: "#101914" }} />
        ) : (
          <img src={media.url} alt="" style={{ width: "100%", height: "100%", objectFit: "cover", display: "block", filter: tone && tone !== "none" ? tone : undefined }} />
        )
      ) : (
        <div style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--muted)", fontSize: compact ? 10 : 12 }}>无媒体</div>
      )}
      <div className="mono" style={{ position: "absolute", top: compact ? 6 : 10, left: compact ? 7 : 12, fontSize: compact ? 8.5 : 10, color: "rgba(255,255,255,.86)", letterSpacing: ".12em", textShadow: "0 1px 2px rgba(0,0,0,.55)", background: "rgba(0,0,0,.22)", padding: compact ? "2px 5px" : "3px 7px" }}>
        {type === "video" ? "VIDEO" : "IMAGE"} · {role}
      </div>
      {label && (
        <div className="mono" style={{ position: "absolute", bottom: compact ? 6 : 10, left: compact ? 7 : 12, right: compact ? 7 : 12, fontSize: compact ? 8.5 : 10, color: "rgba(255,255,255,.78)", letterSpacing: ".08em", textShadow: "0 1px 2px rgba(0,0,0,.55)", display: "flex", justifyContent: "space-between", gap: 8 }}>
          <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{label}</span>
          {media?.recognition === false && <span>NON-AI</span>}
        </div>
      )}
    </div>
  );
}

function MediaStrip({ media = [], active = 0, onPick, tone }) {
  if (!media.length) return null;
  return (
    <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(72px, 1fr))", gap: 8, marginTop: 10 }}>
      {media.map((m, i) => (
        <button key={m.id || i} type="button" onClick={() => onPick && onPick(i)}
          style={{ padding: 0, border: i === active ? "2px solid var(--accent)" : "1px solid var(--rule)", background: "transparent", cursor: "pointer" }}>
          <MediaPreview media={m} tone={tone} aspect="1 / 1" compact />
        </button>
      ))}
    </div>
  );
}

// ---------- Top bar ----------
function TopBar({ current, onNav }) {
  const [navOpen, setNavOpen] = React.useState(false);
  const links = [
    { k: "home", zh: "首页", en: "Home" },
    { k: "archive", zh: "动物档案", en: "Archive" },
    { k: "upload", zh: "上传", en: "Contribute" },
    { k: "map", zh: "地图", en: "Map" },
    { k: "about", zh: "参与", en: "About" },
    { k: "review", zh: "审核台", en: "Review" },
  ];
  const go = (key) => {
    onNav(key);
    setNavOpen(false);
  };
  return (
    <header className="topbar">
      <div className="topbar-inner">
        <div className="brand" onClick={() => go("home")} style={{ cursor: "pointer" }}>
          <div className="brand-mark">
            达里尼动物城<span className="accent">·</span>野生动物档案
          </div>
          <div className="brand-sub">Dalian Zootown / Named &amp; Known · V1.0</div>
        </div>
        <button
          className="mobile-nav-toggle"
          type="button"
          aria-label={navOpen ? "关闭导航" : "打开导航"}
          aria-expanded={navOpen}
          onClick={() => setNavOpen(v => !v)}
        >
          <span></span><span></span><span></span>
        </button>
        <nav className={"nav" + (navOpen ? " open" : "")}>
          {links.map(l => (
            <a
              key={l.k}
              onClick={() => go(l.k)}
              className={current === l.k ? "active" : ""}
              style={{ cursor: "pointer" }}
            >
              <span>{l.zh}</span>
              <span className="en">{l.en}</span>
            </a>
          ))}
        </nav>
        <div className="topbar-actions">
          <button className="btn btn-sm btn-ghost" onClick={() => go("upload")}>
            上传观察 ↗
          </button>
        </div>
      </div>
    </header>
  );
}

// ---------- Footer ----------
function Footer({ onNav }) {
  return (
    <footer className="footer">
      <div className="footer-grid">
        <div>
          <div className="brand-mark" style={{ fontSize: 16 }}>
            达里尼动物城 · 野生动物档案
          </div>
          <div className="brand-sub" style={{ marginTop: 6 }}>DALIAN ZOOTOWN / NAMED &amp; KNOWN</div>
          <p style={{ marginTop: 18, color: "var(--ink-soft)", fontSize: 12.5, lineHeight: 1.6, maxWidth: 360 }}>
            公益科技项目 · 城市生态参与平台筹备中。
            从梅花鹿到狐狸、斑海豹与海岸鸟类，把城市里的每一次野生动物相遇沉淀成可维护的公共档案。
          </p>
          <div className="mono" style={{ fontSize: 10.5, color: "var(--muted)", marginTop: 20, letterSpacing: ".12em" }}>
            筹备阶段 · V1.0 · 2026 春
          </div>
        </div>
        <div>
          <h4>项目 Project</h4>
          <ul>
            <li><a>项目愿景</a></li>
            <li><a>机制设计</a></li>
            <li><a>实施阶段</a></li>
            <li><a>里程碑</a></li>
          </ul>
        </div>
        <div>
          <h4>参与 Join</h4>
          <ul>
            <li><a>上传观察</a></li>
            <li><a>成为志愿审核员</a></li>
            <li><a>命名共创</a></li>
            <li><a>学校合作</a></li>
          </ul>
        </div>
        <div>
          <h4>信息治理 Ethics</h4>
          <ul>
            <li><a>文明观察须知</a></li>
            <li><a>位置信息边界</a></li>
            <li><a>内容审核规则</a></li>
            <li><a>合作与联系</a></li>
          </ul>
        </div>
      </div>
      <div style={{ maxWidth: 1280, margin: "48px auto 0", padding: "0 40px", display: "flex", justifyContent: "space-between", alignItems: "center", fontFamily: "JetBrains Mono, monospace", fontSize: 10.5, color: "var(--muted)", letterSpacing: ".12em" }}>
        <span>© 2026 DALIAN ZOOTOWN · CIVIC-TECH FOR URBAN WILDLIFE</span>
        <span style={{ display: "flex", gap: 20, alignItems: "center" }}>
          <a onClick={() => onNav && onNav("admin")} style={{ cursor: "pointer", color: "var(--muted)", textDecoration: "none", borderBottom: "1px dotted var(--muted)" }} title="内部使用">
            ADMIN ↗
          </a>
          <span>SERVER TIME · 2026-04-18 10:42 CST</span>
        </span>
      </div>
    </footer>
  );
}

// ---------- Tweaks panel ----------
function TweaksPanel({ open, theme, setTheme, dark, setDark, onClose }) {
  if (!open) return null;
  return (
    <div className={"tweaks on"}>
      <div className="tweaks-title">
        <span>Tweaks · 微调</span>
        <span onClick={onClose} style={{ cursor: "pointer" }}>✕</span>
      </div>
      <div className="tweaks-row">
        <div className="tweaks-label">Theme · 主题</div>
        <div className="tweaks-opts">
          {[
            { k: "warm", l: "温润" },
            { k: "forest", l: "森林" },
            { k: "mono", l: "极简" },
          ].map(t => (
            <button key={t.k} className={"tweaks-opt" + (theme === t.k ? " on" : "")} onClick={() => setTheme(t.k)}>
              {t.l}
            </button>
          ))}
        </div>
      </div>
      <div className="tweaks-row">
        <div className="tweaks-label">Mode · 模式</div>
        <div className="tweaks-opts">
          <button className={"tweaks-opt" + (!dark ? " on" : "")} onClick={() => setDark(false)}>明亮</button>
          <button className={"tweaks-opt" + (dark ? " on" : "")} onClick={() => setDark(true)}>深夜</button>
        </div>
      </div>
      <div className="tweaks-row" style={{ fontSize: 10.5, color: "var(--muted)", marginTop: 16, fontFamily: "JetBrains Mono, monospace", letterSpacing: ".08em", borderTop: "1px dashed var(--rule)", paddingTop: 12 }}>
        Toggle Tweaks from toolbar to hide.
      </div>
    </div>
  );
}

Object.assign(window, { Portrait, TopBar, Footer, TweaksPanel, normalizeMediaType, getSightingMedia, MediaPreview, MediaStrip });
