/* PostsView — the working list (M1 CRUD + filters) with a native Kanban board
   (List / Board toggle). Dragging a card between columns runs the same gated
   /transition, so moving to Approved / Scheduled still enforces sign-off. Also
   syncs to the ClickUp board (system of record). */
(function () {
  const D = window.CROPR_DATA;
  const R = window.CroprRules;
  const S = window.CroprStore;
  const fmtSched = (iso) => { try { return new Date(iso).toLocaleString("en-GB", { weekday: "short", day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" }); } catch (e) { return ""; } };
  const shortSched = (iso) => { try { return new Date(iso).toLocaleString("en-GB", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" }); } catch (e) { return ""; } };
  const chanAvatars = (channels, size = 20) => (channels || []).map((ch, i) => { const m = D.CHANNELS[ch]; if (!m) return null; return <span key={ch} style={{ marginLeft: i ? -6 : 0, border: "2px solid var(--surface)", borderRadius: 999 }}><Avatar color={m.avatar} initials={m.initials} src={m.icon} size={size} /></span>; });
  // shared column widths so the list header lines up over the row cells
  const COLS = "minmax(0,1fr) 104px 66px 128px 108px";

  function Filter({ value, onChange, options, allLabel }) {
    return <Select value={value} onChange={onChange} style={{ width: "auto", minWidth: 130 }}
      options={[{ value: "", label: allLabel }, ...options]} />;
  }

  function Row({ post, onOpen, onToast, onDelete }) {
    const rc = R.validatePost(post);
    const errs = rc.flags.filter((f) => f.severity === "error").length;
    const warns = rc.flags.filter((f) => f.severity === "warn").length;
    return (
      <div style={{ display: "grid", gridTemplateColumns: COLS, gap: 16, alignItems: "center",
        padding: "13px 16px", borderBottom: "1px solid var(--border)" }}
        onMouseEnter={(e) => (e.currentTarget.style.background = "var(--bg-subtle)")}
        onMouseLeave={(e) => (e.currentTarget.style.background = "transparent")}>
        <div style={{ minWidth: 0, display: "flex", gap: 12, alignItems: "center" }}>
          <HoverImage src={postThumb(post) || NO_VISUAL} size={42} radius={9} label={post.title} />
          <div style={{ minWidth: 0, cursor: "pointer", flex: 1 }} onClick={() => onOpen(post.id)}>
          <div style={{ fontSize: 14, fontWeight: 700, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{post.title}</div>
          <div style={{ fontSize: 11.5, color: "var(--fg3)", marginTop: 2, display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center" }}>
            <span>{D.label(D.PILLARS, post.pillar)}</span><span>·</span><span>{D.label(D.SERIES, post.series)}</span>
            {post.campaign && <><span>·</span><span>{post.campaign}</span></>}
            {post.scheduleAt && <span style={{ display: "inline-flex", alignItems: "center", gap: 4, color: "var(--accent)", fontWeight: 600 }}><Icon name="calendar-clock" size={12} color="var(--accent)" />{fmtSched(post.scheduleAt)}</span>}
            {S.atRisk(post) && <Badge color="#C6362B" bg="var(--danger-bg)" dot>At risk · due soon</Badge>}
          </div>
          </div>
        </div>
        <div style={{ display: "flex", justifyContent: "center" }}>{chanAvatars(post.channels, 22)}</div>
        <div style={{ display: "flex", justifyContent: "center" }}>
          {errs ? <Badge color="#C6362B" bg="var(--danger-bg)" dot>{errs}</Badge>
            : warns ? <Badge color="#B25E09" bg="var(--warning-bg)" dot>{warns}</Badge>
              : <Badge color="#0E8A50" bg="var(--success-bg)" dot>OK</Badge>}
        </div>
        <div style={{ display: "flex", justifyContent: "center" }}><StatusBadge status={post.status} /></div>
        <div style={{ display: "flex", gap: 4, justifyContent: "flex-end" }}>
          <button title="Open" onClick={() => onOpen(post.id)} style={iconBtn}><Icon name="pen-line" size={16} color="var(--fg2)" /></button>
          <button title="Duplicate" onClick={() => { S.duplicate(post.id); onToast("Duplicated"); }} style={iconBtn}><Icon name="copy" size={16} color="var(--fg2)" /></button>
          <button title="Delete" onClick={() => onDelete && onDelete(post)} style={iconBtn}><Icon name="trash-2" size={16} color="var(--fg3)" /></button>
        </div>
      </div>
    );
  }
  const iconBtn = { border: 0, background: "transparent", cursor: "pointer", width: 30, height: 30, borderRadius: 8, display: "grid", placeItems: "center" };

  // ---- Kanban ----------------------------------------------------------
  function KanbanCard({ post, onOpen, onDragStart, onDragEnd }) {
    const rc = R.validatePost(post);
    const errs = rc.flags.filter((f) => f.severity === "error").length;
    const warns = rc.flags.filter((f) => f.severity === "warn").length;
    return (
      <div draggable
        onDragStart={(e) => { e.dataTransfer.effectAllowed = "move"; try { e.dataTransfer.setData("text/plain", post.id); } catch (x) {} onDragStart(post.id); }}
        onDragEnd={onDragEnd}
        onClick={() => onOpen(post.id)}
        style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 10, padding: "10px 11px", marginBottom: 8, cursor: "grab", boxShadow: "var(--shadow-xs)" }}
        onMouseEnter={(e) => (e.currentTarget.style.borderColor = "var(--border-strong)")}
        onMouseLeave={(e) => (e.currentTarget.style.borderColor = "var(--border)")}>
        <img src={postThumb(post) || NO_VISUAL} alt="" style={{ width: "100%", height: 96, objectFit: "cover", borderRadius: 7, marginBottom: 8, display: "block", border: "1px solid var(--border)" }} />
        <div style={{ fontSize: 13, fontWeight: 700, lineHeight: 1.3, display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden" }}>{post.title}</div>
        <div style={{ fontSize: 10.5, color: "var(--fg3)", margin: "4px 0 8px" }}>{D.label(D.PILLARS, post.pillar)}</div>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <div style={{ display: "flex" }}>{chanAvatars(post.channels, 19)}</div>
          <div style={{ flex: 1 }} />
          {S.atRisk(post) && <span title="At risk — schedule approaching" style={{ display: "inline-flex" }}><Icon name="alert-triangle" size={13} color="#F04438" /></span>}
          {post.scheduleAt && <span style={{ fontSize: 10, color: "var(--accent)", fontWeight: 600, display: "inline-flex", alignItems: "center", gap: 2 }}><Icon name="calendar-clock" size={11} color="var(--accent)" />{shortSched(post.scheduleAt)}</span>}
          {errs ? <Badge color="#C6362B" bg="var(--danger-bg)" dot>{errs}</Badge>
            : warns ? <Badge color="#B25E09" bg="var(--warning-bg)" dot>{warns}</Badge>
              : <Badge color="#0E8A50" bg="var(--success-bg)" dot>OK</Badge>}
        </div>
      </div>
    );
  }

  function Kanban({ posts, onOpen, onToast }) {
    const [dragId, setDragId] = React.useState(null);
    const [overCol, setOverCol] = React.useState(null);
    const drop = (st) => {
      const id = dragId; setDragId(null); setOverCol(null);
      if (!id) return;
      const post = S.get(id);
      if (!post || post.status === st) return;
      const r = S.transition(id, st);
      onToast(r.ok ? `Moved to ${S.stageLabel(st)}` : r.reason, r.ok ? "ok" : "error");
    };
    const workflow = S.getWorkflow();
    return (
      <div>
        <div style={{ fontSize: 11.5, color: "var(--fg3)", marginBottom: 10, display: "flex", alignItems: "center", gap: 6 }}>
          <Icon name="move" size={13} color="var(--fg4)" />Drag cards between columns to move them through the workflow — the responsible person for the destination stage is notified. Edit the stages in Settings → Workflow.
        </div>
        <div style={{ display: "flex", gap: 12, overflowX: "auto", paddingBottom: 12 }}>
          {workflow.map((s) => {
            const items = posts.filter((p) => p.status === s.key);
            const on = overCol === s.key;
            const color = (D.STATUS_MAP[s.key] || {}).color || "var(--fg4)";
            return (
              <div key={s.key}
                onDragOver={(e) => { e.preventDefault(); e.dataTransfer.dropEffect = "move"; if (overCol !== s.key) setOverCol(s.key); }}
                onDrop={(e) => { e.preventDefault(); drop(s.key); }}
                style={{ width: 244, flex: "none", background: on ? "var(--accent-weak)" : "var(--bg-subtle)", border: `1px solid ${on ? "var(--accent)" : "var(--border)"}`, borderRadius: 14, padding: 10, display: "flex", flexDirection: "column", maxHeight: "72vh", boxSizing: "border-box", transition: "background 120ms, border-color 120ms" }}>
                <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "2px 4px 10px" }}>
                  <span style={{ width: 9, height: 9, borderRadius: 3, background: color }} />
                  <span style={{ fontSize: 12, fontWeight: 700, color: "var(--fg1)" }}>{s.name}</span>
                  <div style={{ flex: 1 }} />
                  <span style={{ fontSize: 11, fontWeight: 700, color: "var(--fg3)", background: "var(--bg-muted)", borderRadius: 999, padding: "1px 8px" }}>{items.length}</span>
                </div>
                <div style={{ overflowY: "auto", flex: 1, minHeight: 40 }}>
                  {items.map((p) => <KanbanCard key={p.id} post={p} onOpen={onOpen} onDragStart={setDragId} onDragEnd={() => { setDragId(null); setOverCol(null); }} />)}
                  {items.length === 0 && <div style={{ fontSize: 11, color: "var(--fg4)", textAlign: "center", padding: "18px 0", border: "1px dashed var(--border)", borderRadius: 10 }}>{on ? "Drop here" : "—"}</div>}
                </div>
              </div>
            );
          })}
        </div>
      </div>
    );
  }

  function PostsView({ posts, onOpen, onNew, onToast }) {
    const [q, setQ] = React.useState("");
    const [status, setStatus] = React.useState("");
    const [channel, setChannel] = React.useState("");
    const [series, setSeries] = React.useState("");
    const [mode, setMode] = React.useState("list");
    const [toDelete, setToDelete] = React.useState(null); // post pending delete confirmation

    let list = posts.slice();
    if (q) list = list.filter((p) => (p.title + " " + p.brief + " " + p.content.map((v) => v.body).join(" ")).toLowerCase().includes(q.toLowerCase()));
    if (status && mode === "list") list = list.filter((p) => p.status === status);
    if (channel) list = list.filter((p) => p.channels.includes(channel));
    if (series) list = list.filter((p) => p.series === series);

    return (
      <div style={{ maxWidth: "var(--page-w)", margin: "0 auto" }}>
        <div style={{ display: "flex", gap: 10, alignItems: "center", marginBottom: 16, flexWrap: "wrap" }}>
          <div style={{ position: "relative", flex: 1, minWidth: 180 }}>
            <span style={{ position: "absolute", left: 11, top: "50%", transform: "translateY(-50%)" }}><Icon name="search" size={16} color="var(--fg4)" /></span>
            <TextInput value={q} onChange={setQ} placeholder="Search posts…" style={{ paddingLeft: 34 }} />
          </div>
          {mode === "list" && <Filter value={status} onChange={setStatus} allLabel="All statuses" options={S.getWorkflow().map((s) => ({ value: s.key, label: s.name }))} />}
          <Filter value={channel} onChange={setChannel} allLabel="All channels" options={D.CHANNEL_ORDER.map((c) => ({ value: c, label: D.CHANNELS[c].name + " · " + ((D.PLATFORMS.find((p) => p.id === D.CHANNELS[c].platform) || {}).label || D.CHANNELS[c].platform) }))} />
          <Filter value={series} onChange={setSeries} allLabel="All series" options={D.SERIES.map((s) => ({ value: s.id, label: s.label }))} />
          <Segmented value={mode} onChange={setMode} options={[{ value: "list", label: "List", icon: "list" }, { value: "board", label: "Board", icon: "layout-grid" }]} />
          <Button variant="primary" icon="plus" onClick={onNew}>New post</Button>
        </div>

        {mode === "board" ? (
          <Kanban posts={list} onOpen={onOpen} onToast={onToast} />
        ) : (
          <Card pad={0}>
            <div style={{ display: "grid", gridTemplateColumns: COLS, gap: 16, padding: "10px 16px", borderBottom: "1px solid var(--border)", background: "var(--bg-subtle)", borderRadius: "16px 16px 0 0" }}>
              {["Post", "Channels", "Rules", "Status", ""].map((h, i) => <div key={i} style={{ fontSize: 10.5, fontWeight: 700, color: "var(--fg3)", textTransform: "uppercase", letterSpacing: ".05em", display: "flex", alignItems: "center", justifyContent: i === 0 ? "flex-start" : (i === 4 ? "flex-end" : "center") }}>{h}</div>)}
            </div>
            {list.length === 0
              ? <div style={{ padding: 40, textAlign: "center", color: "var(--fg3)", fontSize: 13 }}>No posts match these filters.</div>
              : list.map((p) => <Row key={p.id} post={p} onOpen={onOpen} onToast={onToast} onDelete={setToDelete} />)}
          </Card>
        )}

        <ConfirmDialog open={!!toDelete} title="Delete this post?" confirmLabel="Delete post"
          message={toDelete ? `“${toDelete.title}” will be permanently removed. This can't be undone.` : ""}
          onCancel={() => setToDelete(null)}
          onConfirm={() => { const t = toDelete.title; S.remove(toDelete.id); setToDelete(null); onToast(`Deleted “${t}”`); }} />

        <div style={{ display: "flex", justifyContent: "center", marginTop: 16 }}>
          <a href="https://app.clickup.com" target="_blank" rel="noreferrer" style={{ fontSize: 12.5, color: "var(--fg3)", display: "flex", alignItems: "center", gap: 6 }}>
            <Icon name="external-link" size={14} color="var(--fg3)" />This board syncs to the ClickUp Social Content Calendar — open it in ClickUp
          </a>
        </div>
      </div>
    );
  }
  window.PostsView = PostsView;
})();
