// Approvals, Media Library, Link in Bio

function ApprovalsPage() {
  const hub = window.useClearCast();
  const [filter, setFilter] = React.useState("pending");
  const [activeId, setActiveId] = React.useState(null);
  const [note, setNote] = React.useState("");
  const [comment, setComment] = React.useState("");
  const [channelFilter, setChannelFilter] = React.useState("all");
  const [authorFilter, setAuthorFilter] = React.useState("all");
  const posts = hub.data.posts || [];
  const media = hub.data.media || [];
  const reviewable = posts.filter((post) => ["needs_approval", "scheduled", "rejected", "changes_requested", "blocked", "failed"].includes(post.status));
  const counts = {
    pending: reviewable.filter((post) => post.status === "needs_approval" || post.status === "changes_requested").length,
    approved: reviewable.filter((post) => post.status === "scheduled").length,
    rejected: reviewable.filter((post) => ["rejected", "blocked", "failed"].includes(post.status)).length,
    all: reviewable.length
  };
  const authors = [...new Set(reviewable.map((post) => post.author || post.createdBy || post.owner || "Emma").filter(Boolean))];
  const filtered = reviewable.filter((post) => {
    if (filter === "pending") return post.status === "needs_approval" || post.status === "changes_requested";
    if (filter === "approved") return post.status === "scheduled";
    if (filter === "rejected") return ["rejected", "blocked", "failed"].includes(post.status);
    return true;
  }).filter((post) => channelFilter === "all" || (post.platforms || []).includes(channelFilter))
    .filter((post) => authorFilter === "all" || (post.author || post.createdBy || post.owner || "Emma") === authorFilter);
  const cur = filtered.find((post) => post.id === activeId) || filtered[0] || reviewable[0];

  React.useEffect(() => {
    if (cur && activeId !== cur.id) setActiveId(cur.id);
  }, [cur?.id]);

  const statusLabel = (status) => ({
    needs_approval: "Pending",
    scheduled: "Approved",
    rejected: "Rejected",
    blocked: "Blocked",
    failed: "Failed",
    changes_requested: "Changes requested",
    draft: "Draft",
    published: "Published"
  }[status] || status);
  const statusPill = (status) => status === "scheduled" ? "green" : ["rejected", "blocked", "failed"].includes(status) ? "danger" : "warn";
  const assetFor = (post) => media.find((asset) => (post.media || []).includes(asset.id) || (post.media || []).includes(asset.url) || (post.media || []).includes(asset.fileName));
  const previewAsset = cur ? assetFor(cur) : null;
  const history = [...(cur?.approvalHistory || []), ...(cur?.activityHistory || [])].sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)));
  const comments = cur?.approvalComments || [];
  const reviewers = cur?.approvers?.length ? cur.approvers : [
    { name: "Maya Chen", role: "Reviewer", status: cur?.status === "scheduled" ? "approved" : "pending" },
    { name: "Jordan Ellis", role: "Approver", status: cur?.status === "scheduled" ? "approved" : "pending" }
  ];
  const publishAttempts = cur?.publishAttempts || [];
  const latestAttempt = publishAttempts[0];
  const canPublish = cur && cur.status === "scheduled";
  const canRetry = cur && ["failed", "blocked"].includes(cur.status);

  const runAction = async (action) => {
    if (!cur) return;
    try {
      await hub.actions.approvalAction(cur.id, action, note);
      setNote("");
      setActiveId(cur.id);
    } catch (error) {
      hub.toast(error.message || "Action failed");
    }
  };

  const addComment = async () => {
    if (!cur || !comment.trim()) {
      hub.toast("Write a comment first");
      return;
    }
    try {
      await hub.actions.approvalComment(cur.id, comment);
      setComment("");
      setActiveId(cur.id);
    } catch (error) {
      hub.toast(error.message || "Could not add comment");
    }
  };

  const runPublish = async (retry = false) => {
    if (!cur) return;
    try {
      await hub.actions.publishPost(cur.id, retry);
      setActiveId(cur.id);
    } catch (error) {
      setActiveId(cur.id);
    }
  };

  return (
    <div className="page">
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 18 }}>
        <div style={{ display: "flex", gap: 10 }}>
          <div className="tabs">
            <button className={`tab ${filter === "pending" ? "active" : ""}`} onClick={() => setFilter("pending")}>Pending <span style={{ color: "var(--warn)", marginLeft: 4 }}>{counts.pending}</span></button>
            <button className={`tab ${filter === "approved" ? "active" : ""}`} onClick={() => setFilter("approved")}>Approved <span style={{ color: "var(--accent-2)", marginLeft: 4 }}>{counts.approved}</span></button>
            <button className={`tab ${filter === "rejected" ? "active" : ""}`} onClick={() => setFilter("rejected")}>Rejected <span style={{ color: "var(--danger)", marginLeft: 4 }}>{counts.rejected}</span></button>
            <button className={`tab ${filter === "all" ? "active" : ""}`} onClick={() => setFilter("all")}>All <span style={{ color: "var(--text-3)", marginLeft: 4 }}>{counts.all}</span></button>
          </div>
        </div>
        <div style={{ display: "flex", gap: 10 }}>
          <select className="input" value={channelFilter} onChange={(event) => setChannelFilter(event.target.value)} style={{ width: 150, height: 36, fontSize: 12.5 }}>
            <option value="all">All channels</option>
            {Object.keys(Platforms).slice(0, 7).map((id) => <option key={id} value={id}>{Platforms[id].name}</option>)}
          </select>
          <select className="input" value={authorFilter} onChange={(event) => setAuthorFilter(event.target.value)} style={{ width: 140, height: 36, fontSize: 12.5 }}>
            <option value="all">All authors</option>
            {authors.map((name) => <option key={name} value={name}>{name}</option>)}
          </select>
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1fr) 420px", gap: 16 }}>
        <div className="card" style={{ padding: 0 }}>
          {filtered.map((post, i) => {
            const isActive = post.id === cur?.id;
            const pColor = post.status === "rejected" ? "var(--danger)" : post.status === "scheduled" ? "var(--accent)" : "var(--warn)";
            const asset = assetFor(post);
            return (
              <div key={post.id} role="button" tabIndex="0" onClick={() => setActiveId(post.id)} style={{
                width: "100%", textAlign: "left",
                display: "grid", gridTemplateColumns: "auto 48px 1fr auto auto", gap: 14, alignItems: "center",
                padding: "16px 20px",
                borderBottom: i < filtered.length - 1 ? "1px solid var(--border)" : "none",
                background: isActive ? "var(--card-2)" : "transparent",
                borderLeft: isActive ? "2px solid var(--accent)" : "2px solid transparent",
              }}>
                <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
                  <input type="checkbox" style={{ accentColor: "var(--accent)" }}/>
                  <span style={{ width: 6, height: 6, borderRadius: 999, background: pColor }}/>
                </div>
                <div style={{ width: 48, height: 48, borderRadius: 8, background: "var(--elev)", position: "relative", overflow: "hidden" }}>
                  {asset?.type === "image" && <img src={asset.url} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }} />}
                  <div style={{ position: "absolute", bottom: -4, right: -4, background: "var(--bg)", padding: 1, borderRadius: 4 }}>
                    <PlatformIcon id={post.platforms?.[0] || "instagram"} size={16} />
                  </div>
                </div>
                <div style={{ minWidth: 0 }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 2 }}>
                    <span style={{ fontSize: 11.5, color: "var(--text-3)" }}>{post.approvers?.[0]?.name || "Maya Chen"}</span>
                    <span style={{ fontSize: 11, color: "var(--text-3)" }}>·</span>
                    <span style={{ fontSize: 11.5, color: "var(--text-3)" }}>{post.date} · {post.time}</span>
                  </div>
                  <div style={{ fontSize: 13, color: "var(--text)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                    {post.caption}
                  </div>
                </div>
                <div style={{ display: "flex", gap: 4 }}>
                  {[1, 2].map(j => (
                    <div key={j} className="avatar sz-28" style={{ background: j === 1 ? "linear-gradient(135deg, #f4c2a1, #d99c70)" : "linear-gradient(135deg, #a08266, #5e4632)", color: "white", fontSize: 10, border: "2px solid var(--card)", marginLeft: j > 1 ? -10 : 0 }}>
                      {j === 1 ? "EW" : "JE"}
                    </div>
                  ))}
                </div>
                <div style={{ display: "flex", gap: 6 }}>
                  <span className={`pill ${statusPill(post.status)}`}>{statusLabel(post.status)}</span>
                </div>
              </div>
            );
          })}
          {!filtered.length && <div className="empty-note" style={{ margin: 18 }}>No posts match this approval view.</div>}
        </div>

        {cur ? <div style={{ display: "flex", flexDirection: "column", gap: 14, position: "sticky", top: 88 }}>
          <div className="card">
            <div className="card-h">
              <h3>Preview</h3>
              <div style={{ display: "flex", gap: 8 }}>
                <PlatformIcon id={cur.platforms?.[0] || "instagram"} size={22} />
                <span className={`pill ${statusPill(cur.status)}`}><span className="pill-dot"/>{statusLabel(cur.status)}</span>
              </div>
            </div>
            <div style={{ width: "100%", aspectRatio: "1/1", background: "var(--bg-2)", borderRadius: 12, marginBottom: 12, overflow: "hidden", display: "grid", placeItems: "center" }}>
              {previewAsset?.type === "image"
                ? <img src={previewAsset.url} alt={previewAsset.name} style={{ width: "100%", height: "100%", objectFit: "cover" }} />
                : <div className="imgph" style={{ width: "100%", height: "100%" }}>{previewAsset?.name || "No media attached"}</div>}
            </div>
            <div style={{ fontSize: 13, lineHeight: 1.55 }}>
              {cur.caption}
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", marginTop: 14, fontSize: 12, color: "var(--text-3)" }}>
              <span>{cur.caption.length} / 2,200 chars</span>
              <span>{cur.date} · {cur.time}</span>
            </div>
          </div>

          <div className="card">
            <div className="card-h">
              <h3>Reviewers</h3>
              <span className={`pill ${statusPill(cur.status)}`}>{reviewers.filter((r) => r.status === "approved").length} / {reviewers.length} approved</span>
            </div>
            {reviewers.map((r, index) => (
              <div key={r.name} style={{ display: "flex", alignItems: "center", gap: 10, padding: "8px 0", borderTop: "1px solid var(--border)" }}>
                <div className="avatar sz-36" style={{ background: index ? "linear-gradient(135deg, #b8c8d8, #4a5a6a)" : "linear-gradient(135deg, #ffc8a3, #8c5a3a)", color: "white" }}>{r.name.split(" ").map(w => w[0]).join("")}</div>
                <div style={{ flex: 1, lineHeight: 1.2 }}>
                  <div style={{ fontSize: 13, fontWeight: 500 }}>{r.name}</div>
                  <div style={{ fontSize: 11.5, color: "var(--text-3)" }}>{r.role}</div>
                </div>
                <span className={`pill ${r.status === "approved" ? "green" : r.status === "rejected" ? "danger" : "warn"}`}>{r.status}</span>
              </div>
            ))}
          </div>

          <div className="card">
            <div className="card-h">
              <h3>Publishing Queue</h3>
              <span className={`pill ${cur.status === "published" ? "green" : cur.status === "failed" || cur.status === "blocked" ? "danger" : cur.status === "scheduled" ? "info" : "warn"}`}>{statusLabel(cur.status)}</span>
            </div>
            <div style={{ display: "grid", gap: 8, fontSize: 12.5 }}>
              <div style={{ display: "flex", justifyContent: "space-between" }}><span className="muted">Queue state</span><b>{cur.publishState || cur.status}</b></div>
              <div style={{ display: "flex", justifyContent: "space-between" }}><span className="muted">Attempts</span><b>{publishAttempts.length}</b></div>
              <div style={{ display: "flex", justifyContent: "space-between" }}><span className="muted">Last run</span><b>{cur.lastPublishAttemptAt ? new Date(cur.lastPublishAttemptAt).toLocaleString() : "Not run"}</b></div>
              {cur.lastPublishError && <div style={{ padding: 10, borderRadius: 10, background: "rgba(239,68,68,0.08)", border: "1px solid rgba(239,68,68,0.25)", color: "var(--danger)" }}>{cur.lastPublishError}</div>}
              {latestAttempt && (
                <div style={{ borderTop: "1px solid var(--border)", paddingTop: 8 }}>
                  <div className="muted" style={{ fontSize: 11, marginBottom: 4 }}>Latest attempt</div>
                  <div style={{ display: "flex", justifyContent: "space-between" }}><span>{latestAttempt.platforms?.length || 0} channels</span><b>{latestAttempt.status}</b></div>
                </div>
              )}
            </div>
            <div style={{ display: "flex", gap: 8, marginTop: 12 }}>
              <button className="btn btn-primary" disabled={!canPublish} onClick={() => runPublish(false)} style={{ flex: 1, opacity: canPublish ? 1 : 0.5 }}>
                <Icon.Upload width="14" height="14" /> Publish now
              </button>
              <button className="btn" disabled={!canRetry} onClick={() => runPublish(true)} style={{ flex: 1, opacity: canRetry ? 1 : 0.5 }}>
                Retry
              </button>
            </div>
          </div>

          <div className="card">
            <div className="card-h"><h3>Comments</h3></div>
            <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
              {comments.map((item) => (
                <div key={item.id} style={{ display: "flex", gap: 10 }}>
                  <div className="avatar sz-28" style={{ background: "linear-gradient(135deg, #f4c2a1, #d99c70)", color: "white" }}>{item.author?.split(" ").map(w => w[0]).join("").slice(0, 2) || "EW"}</div>
                  <div style={{ flex: 1, fontSize: 12.5 }}>
                    <div style={{ marginBottom: 2 }}><b>{item.author}</b> <span className="faint" style={{ fontWeight: 400 }}>· {new Date(item.createdAt).toLocaleString()}</span></div>
                    <div className="muted">{item.text}</div>
                  </div>
                </div>
              ))}
              {!comments.length && <div className="muted" style={{ fontSize: 12.5 }}>No review comments yet.</div>}
            </div>
            <div style={{ display: "flex", gap: 8, marginTop: 14 }}>
              <input className="input" value={comment} onChange={(event) => setComment(event.target.value)} placeholder="Leave a comment…"/>
              <button className="btn" onClick={addComment}>Send</button>
            </div>
          </div>

          <div className="card">
            <div className="card-h"><h3>History</h3></div>
            <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
              {history.map((item) => (
                <div key={item.id} style={{ display: "grid", gridTemplateColumns: "auto 1fr", gap: 10, fontSize: 12.5 }}>
                  <span className={`pill ${item.action === "approved" ? "green" : item.action === "rejected" ? "danger" : "warn"}`}>{item.action.replace("_", " ")}</span>
                  <div>
                    <div>{item.note}</div>
                    <div className="faint" style={{ fontSize: 11 }}>{item.actor} · {new Date(item.createdAt).toLocaleString()}</div>
                  </div>
                </div>
              ))}
              {!history.length && <div className="muted" style={{ fontSize: 12.5 }}>No approval history yet.</div>}
            </div>
          </div>

          <div className="card">
            <label className="field-label">Decision note</label>
            <textarea className="textarea" value={note} onChange={(event) => setNote(event.target.value)} placeholder="Optional note for the approval trail…" style={{ minHeight: 72 }} />
          </div>

          <div style={{ display: "flex", gap: 10 }}>
            <button className="btn danger" style={{ flex: 1 }} onClick={() => runAction("reject")}>Reject</button>
            <button className="btn" style={{ flex: 1 }} onClick={() => runAction("changes")}>Request changes</button>
            <button className="btn btn-primary" style={{ flex: 1 }} onClick={() => runAction("approve")}><Icon.Check width="14" height="14" /> Approve</button>
          </div>
          <button className="btn" style={{ width: "100%", marginTop: 8 }} onClick={() => hub.actions.getReviewLink(cur.id)} title="Share a no-login review link with a client — free, unlimited">
            <Icon.Link width="14" height="14" /> Share client review link
          </button>
        </div> : <div className="empty-note">No posts available for approval yet.</div>}
      </div>
    </div>
  );
}

function MediaEditor({ asset, onClose, onSave, onDelete }) {
  const [name, setName] = React.useState(asset.name || "");
  const [folder, setFolder] = React.useState(asset.folder || "all");
  const [tags, setTags] = React.useState((asset.tags || []).join(", "));

  const save = () => onSave({
    name,
    folder,
    tags: tags.split(",").map((tag) => tag.trim()).filter(Boolean)
  });

  return (
    <div className="modal-scrim" role="presentation" onMouseDown={(event) => {
      if (event.target === event.currentTarget) onClose();
    }}>
      <div className="modal-panel media-editor" role="dialog" aria-modal="true" aria-label="Manage media">
        <div className="modal-head">
          <div>
            <div className="modal-title">Manage media</div>
            <div className="muted" style={{ fontSize: 12 }}>{asset.fileName}</div>
          </div>
          <button className="icon-btn" aria-label="Close" onClick={onClose}><Icon.X width="18" height="18" /></button>
        </div>

        <div className="media-editor-grid">
          <div className="media-editor-preview">
            {asset.type === "image"
              ? <img src={asset.url} alt={asset.name} />
              : <div className="media-file-preview"><Icon.Play width="30" height="30" /><span>{asset.type}</span></div>}
          </div>
          <div>
            <label className="field-label">Name</label>
            <input className="input" value={name} onChange={(event) => setName(event.target.value)} />
            <label className="field-label" style={{ marginTop: 12 }}>Folder</label>
            <select className="input" value={folder} onChange={(event) => setFolder(event.target.value)}>
              <option value="all">All media</option>
              <option value="summer">Summer 2026</option>
              <option value="ugc">UGC</option>
              <option value="brand">Brand Assets</option>
              <option value="drafts">Drafts</option>
            </select>
            <label className="field-label" style={{ marginTop: 12 }}>Tags</label>
            <input className="input" value={tags} onChange={(event) => setTags(event.target.value)} placeholder="#summer, #launch" />
            <div className="modal-actions">
              <button className="btn danger" onClick={onDelete}>Delete</button>
              <div style={{ flex: 1 }} />
              <button className="btn" onClick={onClose}>Cancel</button>
              <button className="btn btn-primary" onClick={save}>Save media</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function MediaLibraryPage() {
  const hub = window.useClearCast();
  const [view, setView] = React.useState("grid");
  const [folder, setFolder] = React.useState("all");
  const [query, setQuery] = React.useState("");
  const [editing, setEditing] = React.useState(null);
  const [uploading, setUploading] = React.useState(false);
  const [customFolders, setCustomFolders] = React.useState([]);

  const assets = hub.data.media || [];
  const posts = hub.data.posts || [];
  const baseFolders = [
    { id: "all", label: "All media", count: assets.length, ico: "Image" },
    { id: "summer", label: "Summer 2026", count: assets.filter((a) => a.folder === "summer").length, ico: "Folder" },
    { id: "ugc", label: "UGC", count: assets.filter((a) => a.folder === "ugc").length, ico: "Heart" },
    { id: "brand", label: "Brand Assets", count: assets.filter((a) => a.folder === "brand").length, ico: "Star" },
    { id: "drafts", label: "Drafts", count: assets.filter((a) => a.folder === "drafts").length, ico: "Edit" },
  ];
  const folders = [
    ...baseFolders,
    ...customFolders.map((item) => ({ ...item, count: assets.filter((asset) => asset.folder === item.id).length, ico: "Folder" }))
  ];
  const allTags = Array.from(new Set(assets.flatMap((asset) => asset.tags || []))).slice(0, 8);
  const displayAssets = assets
    .filter((asset) => folder === "all" || asset.folder === folder)
    .filter((asset) => {
      const text = `${asset.name} ${(asset.tags || []).join(" ")}`.toLowerCase();
      return !query.trim() || text.includes(query.trim().toLowerCase());
    });
  const storageUsed = assets.reduce((sum, asset) => sum + (asset.size || 0), 0);
  const storageMb = (storageUsed / 1024 / 1024).toFixed(storageUsed > 1024 * 1024 ? 1 : 2);

  const uploadFiles = async (event) => {
    const files = Array.from(event.target.files || []);
    if (!files.length) return;
    try {
      setUploading(true);
      for (const file of files) {
        await hub.actions.uploadMedia(file, folder === "all" ? "summer" : folder);
      }
    } catch (error) {
      console.error(error);
      hub.toast("Media upload failed");
    } finally {
      setUploading(false);
      event.target.value = "";
    }
  };

  const usedCount = (asset) => posts.filter((post) => (post.media || []).some((item) => item === asset.id || item === asset.url || item === asset.fileName)).length;
  const createFolder = () => {
    const label = `New Folder ${customFolders.length + 1}`;
    const id = `folder_${Date.now().toString(36)}`;
    setCustomFolders((items) => [...items, { id, label }]);
    setFolder(id);
    hub.toast(`${label} added for this session`);
  };
  const formatBytes = (bytes) => {
    if (!bytes) return "Unknown size";
    if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
    return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
  };

  return (
    <div className="page" style={{ padding: 0 }}>
      <div style={{ display: "grid", gridTemplateColumns: "240px minmax(0, 1fr)", height: "calc(100vh - 72px)" }}>
        <div style={{ borderRight: "1px solid var(--border)", padding: "20px 14px", overflowY: "auto" }}>
          <label className="btn btn-primary" style={{ width: "100%", justifyContent: "center", marginBottom: 12 }}>
            <Icon.Upload width="14" height="14" /> {uploading ? "Uploading..." : "Upload media"}
            <input type="file" accept="image/*,video/*" multiple onChange={uploadFiles} style={{ display: "none" }} />
          </label>
          <div className="nav-section-label">Folders</div>
          {folders.map(f => {
            const Ico = Icon[f.ico];
            const active = folder === f.id;
            return (
              <button key={f.id} className={`nav-item ${active ? "active" : ""}`} onClick={() => setFolder(f.id)}>
                <Ico className="ico" />
                <span>{f.label}</span>
                <span style={{ marginLeft: "auto", fontSize: 11, color: "var(--text-3)" }}>{f.count}</span>
              </button>
            );
          })}
          <div className="nav-section-label">Tags</div>
          {(allTags.length ? allTags : ["#summer", "#hat", "#bag"]).map(t => (
            <button key={t} className={`nav-item ${query === t ? "active" : ""}`} onClick={() => setQuery(t)}>
              <Icon.Hash className="ico" />
              <span>{t}</span>
            </button>
          ))}

          <div style={{ marginTop: 20, padding: 14, background: "var(--card)", border: "1px solid var(--border)", borderRadius: 12 }}>
            <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 6 }}>Storage</div>
            <div style={{ height: 6, background: "var(--bg-2)", borderRadius: 3, overflow: "hidden", marginBottom: 8 }}>
              <div style={{ width: `${Math.min(100, Math.max(4, storageUsed / 1024 / 1024))}%`, height: "100%", background: "linear-gradient(90deg, var(--accent), var(--accent-2))" }}/>
            </div>
            <div style={{ fontSize: 11, color: "var(--text-3)" }}>{storageMb} MB stored locally</div>
          </div>
        </div>

        <div style={{ padding: "20px 24px", overflowY: "auto" }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 16 }}>
            <div style={{ position: "relative", width: 320 }}>
              <Icon.Search width="14" height="14" style={{ position: "absolute", left: 12, top: "50%", transform: "translateY(-50%)", color: "var(--text-3)" }}/>
              <input className="input" value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Search by name or tag…" style={{ paddingLeft: 32 }}/>
            </div>
            <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
              <button className="btn" onClick={() => setView("list")}><Icon.Filter width="14" height="14" /> Filter</button>
              <div className="tabs">
                <button className={`tab ${view === "grid" ? "active" : ""}`} onClick={() => setView("grid")}><Icon.Grid width="14" height="14" /></button>
                <button className={`tab ${view === "list" ? "active" : ""}`} onClick={() => setView("list")}><Icon.List width="14" height="14" /></button>
              </div>
              <button className="btn btn-primary" onClick={createFolder}><Icon.Plus width="14" height="14" /> New folder</button>
            </div>
          </div>

          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 14 }}>
            <div style={{ fontSize: 14, fontWeight: 600 }}>{folders.find((f) => f.id === folder)?.label || "All media"} <span style={{ color: "var(--text-3)", fontWeight: 400 }}>({displayAssets.length})</span></div>
            <div style={{ fontSize: 12.5, color: "var(--text-3)" }}>Sort by: <span style={{ color: "var(--text)" }}>Recently added</span></div>
          </div>

          {view === "list" ? (
            <table className="tbl">
              <thead>
                <tr><th>Name</th><th>Type</th><th>Folder</th><th>Size</th><th>Used</th><th></th></tr>
              </thead>
              <tbody>
                {displayAssets.map((asset) => (
                  <tr key={asset.id}>
                    <td><button onClick={() => setEditing(asset)} style={{ fontWeight: 500 }}>{asset.name}</button></td>
                    <td className="muted">{asset.type}</td>
                    <td className="muted">{asset.folder || "all"}</td>
                    <td className="muted">{formatBytes(asset.size)}</td>
                    <td className="muted">{usedCount(asset)} posts</td>
                    <td><button className="btn btn-sm" onClick={() => setEditing(asset)}>Manage</button></td>
                  </tr>
                ))}
              </tbody>
            </table>
          ) : (
            <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(180px, 1fr))", gap: 14 }}>
              {displayAssets.map((asset) => (
                <button key={asset.id} className="media-tile" onClick={() => setEditing(asset)}>
                  <div className="media-thumb">
                    {asset.type === "image"
                      ? <img src={asset.url} alt={asset.name} />
                      : <div className="media-file-preview"><Icon.Play width="24" height="24" /><span>{asset.type}</span></div>}
                    {asset.type === "video" && (
                      <div className="media-kind-badge"><Icon.Play width="10" height="10" /> Video</div>
                    )}
                    <div className="media-size-badge">{formatBytes(asset.size)}</div>
                  </div>
                  <div className="media-meta">
                    <div className="media-name">{asset.name}</div>
                    <div className="media-sub">Used in {usedCount(asset)} posts</div>
                  </div>
                </button>
              ))}
              {!displayAssets.length && (
                <div className="bulk-empty-state" style={{ gridColumn: "1 / -1" }}>
                  <Icon.Image width="28" height="28" />
                  <div>No media found. Upload images or videos to start building the library.</div>
                </div>
              )}
            </div>
          )}
        </div>
      </div>
      {editing && (
        <MediaEditor
          asset={editing}
          onClose={() => setEditing(null)}
          onSave={async (payload) => {
            const asset = await hub.actions.updateMedia(editing.id, payload);
            setEditing(asset);
          }}
          onDelete={async () => {
            await hub.actions.deleteMedia(editing.id);
            setEditing(null);
          }}
        />
      )}
    </div>
  );
}

function LinkInBioPage() {
  const hub = window.useClearCast();
  const page = hub.data.linkBioPage || { handle: "emma", displayName: "ClearCast - Summer 2026", bio: "Modern essentials, made in small batches. Summer drop ships May 18.", theme: "warm" };
  const [handle, setHandle] = React.useState(page.handle);
  const [displayName, setDisplayName] = React.useState(page.displayName);
  const [bio, setBio] = React.useState(page.bio);
  const [theme, setTheme] = React.useState(page.theme || "warm");
  const [editing, setEditing] = React.useState(null);
  const [draft, setDraft] = React.useState({ title: "", url: "" });

  React.useEffect(() => {
    setHandle(page.handle);
    setDisplayName(page.displayName);
    setBio(page.bio);
    setTheme(page.theme || "warm");
  }, [page.handle, page.displayName, page.bio, page.theme]);

  const links = [...(hub.data.linkBio || [])].sort((a, b) => (a.order || 0) - (b.order || 0));
  const activeLinks = links.filter((link) => link.active !== false);
  const previewUrl = `/bio/${handle || "emma"}`;

  const savePage = async () => {
    await hub.actions.saveBioPage({ handle, displayName, bio, theme });
  };

  const addLink = async () => {
    const title = draft.title.trim();
    const url = draft.url.trim();
    if (!title || !url) {
      hub.toast("Add a title and URL first");
      return;
    }
    await hub.actions.addBioLink(title, url);
    setDraft({ title: "", url: "" });
  };

  const moveLink = async (link, direction) => {
    await hub.actions.updateBioLink(link.id, { order: Math.max(0, (link.order || 0) + direction) });
  };

  const simulateClick = async (link) => {
    await hub.actions.clickBioLink(link.id);
  };

  return (
    <div className="page">
      <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1fr) 360px", gap: 24 }}>
        {/* Editor */}
        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <div className="card">
            <div className="card-h">
              <h3>Page details</h3>
              <span className="pill green"><span className="pill-dot"/>Live</span>
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
              <div>
                <label className="field-label">Page handle</label>
                <div style={{ display: "flex", alignItems: "center", border: "1px solid var(--border)", borderRadius: 10, padding: "0 12px", background: "var(--bg-2)" }}>
                  <span style={{ fontSize: 13, color: "var(--text-3)" }}>clearcast.co/</span>
                  <input value={handle} onChange={(event) => setHandle(event.target.value)} style={{ flex: 1, padding: "10px 4px", background: "transparent", border: "none", outline: "none", color: "var(--text)", fontSize: 13 }}/>
                  <button className="btn btn-ghost btn-sm" onClick={() => navigator.clipboard?.writeText(`${location.origin}${previewUrl}`)} style={{ padding: 4 }}><Icon.Copy width="13" height="13" /></button>
                </div>
              </div>
              <div>
                <label className="field-label">Display name</label>
                <input className="input" value={displayName} onChange={(event) => setDisplayName(event.target.value)}/>
              </div>
              <div style={{ gridColumn: "1 / -1" }}>
                <label className="field-label">Bio</label>
                <textarea className="textarea" value={bio} onChange={(event) => setBio(event.target.value)} style={{ minHeight: 56, resize: "none" }}/>
              </div>
            </div>
            <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, marginTop: 14 }}>
              <a className="btn" href={previewUrl} target="_blank"><Icon.External width="13" height="13" /> Open public page</a>
              <button className="btn btn-primary" onClick={savePage}>Save page</button>
            </div>
          </div>

          <div className="card">
            <div className="card-h">
              <h3>Links</h3>
              <button onClick={addLink} className="btn btn-primary btn-sm"><Icon.Plus width="12" height="12" /> Add link</button>
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 12 }}>
              <input className="input" value={draft.title} onChange={(event) => setDraft({ ...draft, title: event.target.value })} placeholder="Link title" />
              <input className="input" value={draft.url} onChange={(event) => setDraft({ ...draft, url: event.target.value })} placeholder="https:// or /path" />
            </div>
            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
              {links.map((l, i) => (
                <div key={l.id} style={{ display: "flex", alignItems: "center", gap: 12, padding: 12, background: "var(--bg-2)", border: "1px solid var(--border)", borderRadius: 12, opacity: l.active === false ? 0.55 : 1 }}>
                  <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
                    <button className="icon-btn" style={{ width: 24, height: 20 }} onClick={() => moveLink(l, -1)}><Icon.ChevronUp width="12" height="12" /></button>
                    <button className="icon-btn" style={{ width: 24, height: 20 }} onClick={() => moveLink(l, 1)}><Icon.ChevronDown width="12" height="12" /></button>
                  </div>
                  <div style={{ width: 36, height: 36, borderRadius: 8, background: "var(--elev)", display: "grid", placeItems: "center", color: "var(--accent-2)", fontSize: 16 }}>{l.icon}</div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                      <div style={{ fontSize: 13.5, fontWeight: 500 }}>{l.title}</div>
                      {l.clicks > 1000 && <span className="pill green" style={{ padding: "2px 7px", fontSize: 10 }}>Featured</span>}
                    </div>
                    <div style={{ fontSize: 11.5, color: "var(--text-3)" }}>{l.url}</div>
                  </div>
                  <div style={{ textAlign: "right", fontSize: 12 }}>
                    <div style={{ fontWeight: 600 }}>{l.clicks.toLocaleString()}</div>
                    <div style={{ color: "var(--text-3)", fontSize: 11 }}>clicks (30d)</div>
                  </div>
                  <button className={`btn btn-sm ${l.active !== false ? "btn-primary" : ""}`} onClick={() => hub.actions.updateBioLink(l.id, { active: l.active === false })}>{l.active === false ? "Off" : "On"}</button>
                  <button className="btn btn-sm" onClick={() => simulateClick(l)}>Click</button>
                  <button className="btn btn-sm" onClick={() => setEditing(l)}>Edit</button>
                  <button className="btn danger btn-sm" onClick={() => hub.actions.deleteBioLink(l.id)}>Delete</button>
                </div>
              ))}
              {!links.length && <div className="empty-note">No links yet. Add your first bio link above.</div>}
            </div>
          </div>

          <div className="card">
            <div className="card-h"><h3>Theme</h3></div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 10 }}>
              {[
                { id: "warm", name: "Warm sand", bg: "linear-gradient(180deg, #f4e8d0, #d8b890)" },
                { id: "dark", name: "Midnight", bg: "linear-gradient(180deg, #1a1a1a, #0a0a0a)" },
                { id: "rose", name: "Rose", bg: "linear-gradient(180deg, #ffd8d0, #d88880)" },
                { id: "forest", name: "Forest", bg: "linear-gradient(180deg, #284038, #142420)" },
              ].map(t => (
                  <button key={t.id} onClick={() => setTheme(t.id)} style={{
                  padding: 12,
                  borderRadius: 12,
                  border: theme === t.id ? "1.5px solid var(--accent)" : "1px solid var(--border)",
                  background: "var(--bg-2)",
                  textAlign: "left",
                }}>
                  <div style={{ height: 60, borderRadius: 8, background: t.bg, marginBottom: 8 }}/>
                  <div style={{ fontSize: 12, fontWeight: 500 }}>{t.name}</div>
                </button>
              ))}
            </div>
          </div>
        </div>

        {/* Phone preview */}
        <div style={{ position: "sticky", top: 88 }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 14 }}>
            <div style={{ fontSize: 13.5, color: "var(--text-2)", fontWeight: 500 }}>Preview</div>
            <a className="btn btn-sm" href={previewUrl} target="_blank"><Icon.External width="12" height="12" /> Open page</a>
          </div>
          <div style={{ display: "grid", placeItems: "center" }}>
            <PhoneFrame>
              <div style={{ height: "100%", background: theme === "dark" ? "linear-gradient(180deg, #1a1a1a, #0a0a0a)" : theme === "rose" ? "linear-gradient(180deg, #ffd8d0, #d88880)" : theme === "forest" ? "linear-gradient(180deg, #284038, #142420)" : "linear-gradient(180deg, #f4e8d0, #d8b890)", color: theme === "warm" || theme === "rose" ? "#2a1a0a" : "white", display: "flex", flexDirection: "column" }}>
                <StatusBar dark={theme !== "warm" && theme !== "rose"} />
                <div style={{ display: "flex", flexDirection: "column", alignItems: "center", padding: "16px 20px 12px", textAlign: "center" }}>
                  <div className="brand-mark" style={{ width: 56, height: 56, fontSize: 18, borderRadius: 999, marginBottom: 10 }}>CC</div>
                  <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 2 }}>@{handle}</div>
                  <div style={{ fontSize: 11, opacity: 0.75, lineHeight: 1.4, maxWidth: 200 }}>{bio}</div>
                </div>
                <div style={{ display: "flex", flexDirection: "column", gap: 8, padding: "10px 16px", overflowY: "auto" }}>
                  {activeLinks.map((l) => (
                    <button key={l.id} onClick={() => simulateClick(l)} style={{
                      display: "flex", alignItems: "center", gap: 10,
                      padding: "10px 12px",
                      background: theme === "warm" || theme === "rose" ? "rgba(255,255,255,0.55)" : "rgba(255,255,255,0.08)",
                      borderRadius: 12,
                      backdropFilter: "blur(8px)",
                      border: "1px solid rgba(255,255,255,0.15)",
                    }}>
                      <span style={{ fontSize: 14 }}>{l.icon}</span>
                      <span style={{ fontSize: 11.5, fontWeight: 600, flex: 1 }}>{l.title}</span>
                    </button>
                  ))}
                </div>
                <div style={{ padding: 12, display: "flex", justifyContent: "center", gap: 12, opacity: 0.7 }}>
                  <PlatformIcon id="instagram" size={20} />
                  <PlatformIcon id="tiktok" size={20} />
                  <PlatformIcon id="youtube" size={20} />
                </div>
              </div>
            </PhoneFrame>
          </div>
        </div>
      </div>
      {editing && (
        <BioLinkEditor
          link={editing}
          onClose={() => setEditing(null)}
          onSave={async (payload) => {
            await hub.actions.updateBioLink(editing.id, payload);
            setEditing(null);
          }}
        />
      )}
    </div>
  );
}

function BioLinkEditor({ link, onClose, onSave }) {
  const [title, setTitle] = React.useState(link.title || "");
  const [url, setUrl] = React.useState(link.url || "");
  const [icon, setIcon] = React.useState(link.icon || "✦");

  return (
    <div className="modal-scrim" role="presentation" onMouseDown={(event) => {
      if (event.target === event.currentTarget) onClose();
    }}>
      <div className="modal-panel" role="dialog" aria-modal="true" aria-label="Edit bio link">
        <div className="modal-head">
          <div>
            <div className="modal-title">Edit bio link</div>
            <div className="muted" style={{ fontSize: 12 }}>{link.id}</div>
          </div>
          <button className="icon-btn" aria-label="Close" onClick={onClose}><Icon.X width="18" height="18" /></button>
        </div>
        <label className="field-label">Title</label>
        <input className="input" value={title} onChange={(event) => setTitle(event.target.value)} />
        <label className="field-label" style={{ marginTop: 12 }}>URL</label>
        <input className="input" value={url} onChange={(event) => setUrl(event.target.value)} />
        <label className="field-label" style={{ marginTop: 12 }}>Icon</label>
        <input className="input" value={icon} onChange={(event) => setIcon(event.target.value)} />
        <div className="modal-actions">
          <div style={{ flex: 1 }} />
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn btn-primary" onClick={() => onSave({ title, url, icon })}>Save link</button>
        </div>
      </div>
    </div>
  );
}

window.ApprovalsPage = ApprovalsPage;
window.MediaLibraryPage = MediaLibraryPage;
window.LinkInBioPage = LinkInBioPage;
