// Orders page — list + detail drawer with chat / files / milestones + 3 admin actions

const OrdersPage = () => {
  const [tab, setTab] = useState("all");
  const [query, setQuery] = useState("");
  const [dateRange, setDateRange] = useState("all");
  const [orderType, setOrderType] = useState("all");
  const [amountRange, setAmountRange] = useState("all");
  const [detailOrder, setDetailOrder] = useState(null);
  const [actionDialog, setActionDialog] = useState(null); // { kind, order }
  const [orders, setOrders] = useState([]);
  const [loading, setLoading] = useState(false);
  const [flaggedIds, setFlaggedIds] = useState(new Set());
  const [page, setPage] = useState(0);
  const toast = useToast();

  const loadOrders = () => {
    setLoading(true);
    fetch("/api/admin/orders")
      .then(r => r.ok ? r.json() : null)
      .then(data => { if (Array.isArray(data)) { setOrders(data); window.MOCK.ORDERS = data; } })
      .catch(() => {})
      .finally(() => setLoading(false));
  };
  useEffect(() => { loadOrders(); }, []);

  const toggleFlag = (rawId) => {
    setFlaggedIds(prev => {
      const next = new Set(prev);
      if (next.has(rawId)) next.delete(rawId); else next.add(rawId);
      return next;
    });
  };

  const filtered = orders
    .filter(o => {
      if (tab === "in_progress" && !["in_progress","review"].includes(o.status)) return false;
      if (tab === "completed" && o.status !== "completed") return false;
      if (tab === "disputed" && !["disputed","refund_requested"].includes(o.status)) return false;
      if (tab === "refunded" && o.status !== "refunded") return false;
      if (query) {
        const q = query.toLowerCase();
        if (!o.id.toLowerCase().includes(q) && !o.artistName.includes(query) && !o.clientName.includes(query)) return false;
      }
      if (dateRange !== "all" && o.createdAt) {
        const now = Date.now();
        const created = new Date(o.createdAt.replace(" ", "T")).getTime();
        const days = { "7d": 7, "30d": 30, "90d": 90 }[dateRange];
        if (days && (now - created) > days * 86400000) return false;
      }
      if (orderType === "圖" && o.orderType !== "auction") return false;
      if (orderType === "文" && o.orderType !== "commission") return false;
      if (amountRange === "lt1000" && o.amount >= 1000) return false;
      if (amountRange === "1k-5k" && (o.amount < 1000 || o.amount >= 5000)) return false;
      if (amountRange === "5k-10k" && (o.amount < 5000 || o.amount >= 10000)) return false;
      if (amountRange === "gt10k" && o.amount < 10000) return false;
      return true;
    })
    .sort((a, b) => {
      const af = flaggedIds.has(a._rawId) ? 1 : 0;
      const bf = flaggedIds.has(b._rawId) ? 1 : 0;
      return bf - af;
    });

  useEffect(() => { setPage(0); }, [tab, query, orderType, amountRange, dateRange]);

  const handleAction = (kind, order) => {
    setDetailOrder(null);
    setActionDialog({ kind, order });
  };

  return (
    <div className="fade-in">
      <PageHeader
        title="訂單管理"
        subtitle={`${orders.length} 筆訂單 · 糾紛處理中 ${orders.filter(o => o.status === "disputed").length} 筆`}
        actions={<>
          <Button variant="secondary" icon="refresh" disabled={loading} onClick={loadOrders}>重新整理</Button>
          <Button variant="secondary" icon="download" onClick={() => {
            csvDownload(`orders_${Date.now()}.csv`,
              ["訂單ID","類型","創作者","委託人","金額","平台費","創作者所得","狀態","建立時間"],
              filtered.map(o => [o.id, o.type, o.artistName, o.clientName, o.amount, o.platformFee, o.artistPayout, o.status, o.createdAt])
            );
          }}>匯出</Button>
          <Button variant="secondary" icon="filter">進階篩選</Button>
        </>}
      />

      <div style={{ marginBottom: 16 }}>
        <Tabs
          active={tab} onChange={setTab}
          tabs={[
            { value: "all", label: "全部", count: orders.length },
            { value: "in_progress", label: "進行中", count: orders.filter(o => ["in_progress","review"].includes(o.status)).length },
            { value: "completed", label: "已完成", count: orders.filter(o => o.status === "completed").length },
            { value: "disputed", label: "已中止", count: orders.filter(o => ["disputed","refund_requested","refunded"].includes(o.status)).length },
          ]}
        />
      </div>

      <div style={{ display: "flex", gap: 10, alignItems: "center", marginBottom: 14, flexWrap: "wrap" }}>
        <div style={{ flex: 1, maxWidth: 320, minWidth: 200 }}>
          <Input icon="search" placeholder="訂單編號、創作者、業主…" value={query} onChange={e => setQuery(e.target.value)}/>
        </div>
        <Select value={dateRange} onChange={setDateRange} icon="calendar" options={[
          { value: "all", label: "所有日期" }, { value: "7d", label: "近 7 日" },
          { value: "30d", label: "近 30 日" }, { value: "90d", label: "近 90 日" },
        ]}/>
        <Select value={orderType} onChange={setOrderType} icon="order" options={[
          { value: "all", label: "所有類型" },
          { value: "圖", label: "繪圖" },
          { value: "文", label: "文集" },
        ]}/>
        <Select value={amountRange} onChange={setAmountRange} icon="coin" options={[
          { value: "all", label: "所有金額" },
          { value: "lt1000", label: "< NT$ 1,000" },
          { value: "1k-5k", label: "NT$ 1,000 - 5,000" },
          { value: "5k-10k", label: "NT$ 5,000 - 10,000" },
          { value: "gt10k", label: "≥ NT$ 10,000" },
        ]}/>
        <div style={{ flex: 1 }}/>
        <div style={{ fontSize: 12, color: "var(--ink-3)" }}>{filtered.length} 筆 · 合計 <b className="mono" style={{ color: "var(--ink-2)" }}>NT$ {fmtNum(filtered.reduce((s, o) => s + o.amount, 0))}</b></div>
      </div>

      <Table
        onRowClick={o => setDetailOrder(o)}
        columns={[
          { title: "訂單", render: o => (
            <div style={{ display: "flex", alignItems: "flex-start", gap: 6 }}>
              {flaggedIds.has(o._rawId) && <span style={{ color: "var(--warn)", fontSize: 14, lineHeight: 1.6 }}>★</span>}
              <div>
                <div style={{ fontSize: 13.5, fontWeight: 500 }}>{o.type}</div>
                <div className="mono" style={{ fontSize: 11.5, color: "var(--ink-3)" }}>{o.id}</div>
              </div>
            </div>
          ) },
          { title: "創作者", render: o => {
            const u = MOCK.USERS.find(x => x.id === o.artistId);
            const avatarUrl = o.artistAvatar && !o.artistAvatar.includes("avatar-default") ? o.artistAvatar : null;
            return <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              {avatarUrl
                ? <img src={avatarUrl} style={{ width: 24, height: 24, borderRadius: "50%", objectFit: "cover", flexShrink: 0 }}/>
                : u ? <Avatar hue={u.avatar.hue} glyph={u.avatar.glyph} size={24}/>
                : <Avatar hue={200} glyph={o.artistName?.[0] ?? "?"} size={24}/>}
              <span style={{ fontSize: 13 }}>{o.artistName}</span>
            </div>;
          } },
          { title: "委託人", render: o => {
            const u = MOCK.USERS.find(x => x.id === o.clientId);
            const avatarUrl = o.clientAvatar && !o.clientAvatar.includes("avatar-default") ? o.clientAvatar : null;
            return <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              {avatarUrl
                ? <img src={avatarUrl} style={{ width: 24, height: 24, borderRadius: "50%", objectFit: "cover", flexShrink: 0 }}/>
                : u ? <Avatar hue={u.avatar.hue} glyph={u.avatar.glyph} size={24}/>
                : <Avatar hue={30} glyph={o.clientName?.[0] ?? "?"} size={24}/>}
              <span style={{ fontSize: 13 }}>{o.clientName}</span>
            </div>;
          } },
          { title: "金額", align: "right", render: o => <span className="mono" style={{ fontWeight: 500 }}>{fmtCurrency(o.amount)}</span> },
          { title: "進度", render: o => (
            <div style={{ width: 100 }}>
              <div style={{ height: 4, background: "var(--surface-2)", borderRadius: 999, overflow: "hidden" }}>
                <div style={{
                  height: "100%", width: `${o.progress}%`,
                  background: o.status === "disputed" ? "var(--danger)" : o.progress === 100 ? "var(--success)" : "var(--ink)",
                }}/>
              </div>
              <div className="mono" style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>{o.progress}% · {o.milestones}/{o.totalMilestones}</div>
            </div>
          ) },
          { title: "狀態", render: o => <OrderStatusBadge status={o.status}/> },
          { title: "建立時間", render: o => <span className="mono" style={{ fontSize: 12, color: "var(--ink-3)" }}>{o.createdAt}</span> },
        ]}
        rows={filtered.slice(page * 12, (page + 1) * 12)}
      />
      <Pagination total={filtered.length} pageSize={12} page={page} onPageChange={setPage}/>

      <OrderDetailDrawer
        order={detailOrder}
        onClose={() => setDetailOrder(null)}
        onAction={handleAction}
        flaggedIds={flaggedIds}
        onToggleFlag={toggleFlag}
      />

      {actionDialog && (
        <OrderActionDialog
          kind={actionDialog.kind}
          order={actionDialog.order}
          onClose={() => setActionDialog(null)}
          onConfirm={() => {
            const msg = {
              force_complete: { title: "訂單已強制結案", message: `${actionDialog.order.id} · 款項已撥付創作者` },
              full_refund: { title: "全額退款已送出", message: `${actionDialog.order.id} · NT$ ${fmtNum(actionDialog.order.amount)} 將於 3-5 日內入帳` },
              partial_refund: { title: "部分退款已送出", message: `${actionDialog.order.id} · 退款金額已記錄至審計日誌` },
            }[actionDialog.kind];
            toast({ ...msg, icon: "check" });
            setActionDialog(null);
          }}
        />
      )}
    </div>
  );
};

// ============== Detail drawer ==============

const OrderDetailDrawer = ({ order, onClose, onAction, flaggedIds, onToggleFlag }) => {
  const [tab, setTab] = useState("overview");
  const [contactOpen, setContactOpen] = useState(false);
  const [contactMsg, setContactMsg] = useState("");
  const [contactSending, setContactSending] = useState(false);
  const toast = useToast();
  useEffect(() => { if (order) { setTab(order?.status === "disputed" ? "dispute" : "overview"); setContactOpen(false); setContactMsg(""); } }, [order?.id]);
  if (!order) return null;

  const artist = MOCK.USERS.find(u => u.id === order.artistId) ?? { name: order.artistName, avatar: { hue: 200, glyph: (order.artistName?.[0] ?? "?"), url: order.artistAvatar } };
  const client = MOCK.USERS.find(u => u.id === order.clientId) ?? { name: order.clientName, avatar: { hue: 30, glyph: (order.clientName?.[0] ?? "?"), url: order.clientAvatar } };
  const isFlagged = flaggedIds?.has(order._rawId);

  async function sendContactMsg() {
    if (!contactMsg.trim()) return;
    setContactSending(true);
    try {
      const msg = contactMsg.trim();
      await Promise.all([
        fetch(`/api/admin/users/${order.artistUserId ?? order.artistId}/notify`, {
          method: "POST", headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ type: "admin_message", content: `【訂單 ${order.id}】${msg}` }),
        }),
        fetch(`/api/admin/users/${order.clientId}/notify`, {
          method: "POST", headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ type: "admin_message", content: `【訂單 ${order.id}】${msg}` }),
        }),
      ]);
      toast({ title: "訊息已送出", message: "已分別發送站內信給創作者與業主", icon: "check" });
      setContactOpen(false);
      setContactMsg("");
    } catch {
      toast({ title: "發送失敗", message: "請稍後再試", icon: "x" });
    } finally {
      setContactSending(false);
    }
  }

  return (
    <Drawer open={!!order} onClose={onClose} width={760}>
      <div style={{ padding: "18px 24px", borderBottom: "1px solid var(--border)", display: "flex", alignItems: "center", gap: 12 }}>
        <button onClick={onClose} style={{ padding: 4, color: "var(--ink-3)" }}><Icon name="x" size={18}/></button>
        <div style={{ fontSize: 13, color: "var(--ink-3)" }}>訂單詳情</div>
        <div style={{ flex: 1 }}/>
        <Button variant="ghost" size="sm" icon="copy">複製訂單</Button>
        <Button variant="ghost" size="sm" icon="external">前台預覽</Button>
      </div>

      <div style={{ flex: 1, overflow: "auto", padding: "22px 28px 120px" }}>
        <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 16, marginBottom: 18 }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div className="mono" style={{ fontSize: 12, color: "var(--ink-3)" }}>{order.id}</div>
            <h2 style={{ fontSize: 22, fontWeight: 600, marginTop: 2 }}>{order.type}</h2>
            <div style={{ marginTop: 8, display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }}>
              <OrderStatusBadge status={order.status}/>
              <span style={{ fontSize: 12, color: "var(--ink-3)" }}>建立於 {order.createdAt}</span>
              <span style={{ fontSize: 12, color: "var(--ink-3)" }}>· 截止 {order.deadline}</span>
            </div>
          </div>
          <div style={{ textAlign: "right", flexShrink: 0, minWidth: 180 }}>
            <div style={{ fontSize: 11.5, color: "var(--ink-3)" }}>訂單金額</div>
            <div className="serif" style={{ fontSize: 28, lineHeight: 1.1, whiteSpace: "nowrap" }}>NT$ {fmtNum(order.amount)}</div>
            <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>已完成 <b className="mono" style={{ color: "var(--ink-2)" }}>{order.milestones}/{order.totalMilestones}</b> 階段</div>
          </div>
        </div>

        {/* Parties */}
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginBottom: 16 }}>
          <PartyCard role="創作者" user={artist} roleColor="accent"/>
          <PartyCard role="委託人" user={client} roleColor="info"/>
        </div>

        <div style={{ marginBottom: 18 }}>
          <Tabs active={tab} onChange={setTab} tabs={[
            ...(order.status === "disputed" ? [{ value: "dispute", label: "糾紛內容", tone: "danger" }] : []),
            { value: "overview", label: "總覽" },
            { value: "milestones", label: "階段與交付", count: order.totalMilestones },
            { value: "chat", label: "溝通紀錄" },
            { value: "files", label: "檔案" },
            { value: "payment", label: "金流" },
          ]}/>
        </div>

        {tab === "dispute" && <DisputeTab order={order}/>}
        {tab === "overview" && <OverviewTab order={order}/>}
        {tab === "milestones" && <MilestonesTab order={order}/>}
        {tab === "chat" && <ChatTab order={order}/>}
        {tab === "files" && <FilesTab order={order}/>}
        {tab === "payment" && <PaymentTab order={order}/>}
      </div>

      {/* 連絡雙方 dialog */}
      {contactOpen && (
        <div style={{
          position: "absolute", left: 0, right: 0, bottom: 0, zIndex: 10,
          background: "var(--surface)", borderTop: "2px solid var(--border)",
          padding: "18px 24px 24px",
        }}>
          <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 10 }}>
            發送官方站內信給雙方
          </div>
          <div style={{ fontSize: 11.5, color: "var(--ink-3)", marginBottom: 10 }}>
            訊息將以「堆堆官方」名義，同時發送給創作者 <b>{order.artistName}</b> 與業主 <b>{order.clientName}</b>。
          </div>
          <textarea
            value={contactMsg}
            onChange={e => setContactMsg(e.target.value)}
            placeholder="輸入要發送的訊息…"
            rows={3}
            style={{
              width: "100%", resize: "none", fontSize: 13, padding: "10px 12px",
              border: "1px solid var(--border)", borderRadius: 8, background: "var(--surface-2)",
              outline: "none", boxSizing: "border-box", fontFamily: "inherit",
            }}
          />
          <div style={{ display: "flex", gap: 8, marginTop: 10, justifyContent: "flex-end" }}>
            <Button variant="ghost" onClick={() => { setContactOpen(false); setContactMsg(""); }}>取消</Button>
            <Button variant="primary" onClick={sendContactMsg} disabled={!contactMsg.trim() || contactSending}>
              {contactSending ? "發送中…" : "確認發送"}
            </Button>
          </div>
        </div>
      )}

      {/* Sticky footer actions */}
      {!contactOpen && (
        <div style={{
          position: "absolute", left: 0, right: 0, bottom: 0,
          padding: "14px 24px", borderTop: "1px solid var(--border)",
          background: "var(--surface)", display: "flex", gap: 8, alignItems: "center",
        }}>
          <Button variant="secondary" icon="mail" onClick={() => setContactOpen(true)}>聯絡雙方</Button>
          <Button
            variant="ghost"
            icon="flag"
            style={isFlagged ? { color: "var(--warn)" } : {}}
            onClick={() => { onToggleFlag?.(order._rawId); }}
          >
            {isFlagged ? "取消標記" : "標記案件"}
          </Button>
          <div style={{ flex: 1 }}/>
          {order.status === "disputed" && (
            <Button variant="primary" onClick={() => onAction("force_complete", order)} icon="check">強制結案</Button>
          )}
          {["completed", "refunded", "cancelled"].includes(order.status) && (
            <div style={{ fontSize: 12.5, color: "var(--ink-3)" }}>此訂單已終結，僅可查看</div>
          )}
        </div>
      )}
    </Drawer>
  );
};

// ============== Tab contents ==============

const OverviewTab = ({ order }) => {
  const ms = Array.isArray(order.milestonesData) ? order.milestonesData : [];
  const completedMs = ms.filter(m => m.completed).length;
  const timeline = [
    { label: "訂單建立", time: order.createdAt, done: true },
    { label: "業主付款託管", time: order.createdAt, done: true },
    { label: "創作者開工", time: order.progress > 0 ? order.createdAt : "—", done: order.progress > 0 },
    ...ms.map((m, i) => ({
      label: m.name || `階段 ${i + 1} 交付`,
      time: m.completed ? "—" : "—",
      done: m.completed,
    })),
    { label: "業主驗收", time: "—", done: order.status === "completed" },
    { label: "款項結算", time: "—", done: order.status === "completed" },
  ];
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
      <div>
        <SectionLabel>委託內容</SectionLabel>
        <Card padding={16}>
          <div style={{ fontSize: 13.5, lineHeight: 1.65, color: "var(--ink-2)" }}>
            {order.description || <span style={{ color: "var(--ink-4)", fontStyle: "italic" }}>無委託說明</span>}
            <div style={{ marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--border)", display: "flex", flexWrap: "wrap", gap: 14, fontSize: 12, color: "var(--ink-3)" }}>
              <span>類型:<b style={{ color: "var(--ink-2)" }}>{order.type}</b></span>
              <span>截止:<b style={{ color: "var(--ink-2)" }}>{order.deadline || "—"}</b></span>
              <span>階段:<b style={{ color: "var(--ink-2)" }}>{order.milestones}/{order.totalMilestones}</b></span>
              {(order.tags ?? []).length > 0 && <span>標籤:{(order.tags ?? []).map(t => <Badge key={t} tone="default" size="sm" style={{ marginLeft: 4 }}>{t}</Badge>)}</span>}
            </div>
          </div>
        </Card>
      </div>

      <div>
        <SectionLabel>訂單時間軸</SectionLabel>
        <Card padding={18}>
          <div style={{ position: "relative", paddingLeft: 18 }}>
            <div style={{ position: "absolute", left: 5, top: 8, bottom: 8, width: 1, background: "var(--border-strong)" }}/>
            {timeline.map((t, i) => (
              <div key={i} style={{ display: "flex", gap: 12, padding: "6px 0", position: "relative" }}>
                <div style={{
                  position: "absolute", left: -18, top: 9,
                  width: 11, height: 11, borderRadius: 999,
                  background: t.done ? "var(--ink)" : "var(--surface)",
                  border: "2px solid " + (t.done ? "var(--ink)" : "var(--border-strong)"),
                }}/>
                <div style={{ flex: 1, fontSize: 13, color: t.done ? "var(--ink)" : "var(--ink-3)", fontWeight: t.done ? 500 : 400 }}>{t.label}</div>
                <div className="mono" style={{ fontSize: 11.5, color: "var(--ink-4)" }}>{t.time}</div>
              </div>
            ))}
          </div>
        </Card>
      </div>

      {order.status === "disputed" && (
        <div>
          <SectionLabel>糾紛資訊</SectionLabel>
          <Card padding={16} style={{ borderColor: "var(--danger)", borderWidth: 1, borderStyle: "solid", background: "var(--danger-soft)" }}>
            <div style={{ display: "flex", gap: 10, alignItems: "flex-start" }}>
              <Icon name="alert" size={18} style={{ color: "var(--danger)", marginTop: 2 }}/>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13.5, fontWeight: 500, color: "var(--danger)" }}>調解處理中</div>
                <div style={{ fontSize: 12.5, color: "var(--ink-2)", marginTop: 4, lineHeight: 1.6 }}>
                  請切換至「糾紛內容」分頁，查看委託方需求說明及創作者上傳的稿件。
                </div>
              </div>
            </div>
          </Card>
        </div>
      )}
    </div>
  );
};

const MilestonesTab = ({ order }) => {
  const rawMs = Array.isArray(order.milestonesData) && order.milestonesData.length > 0
    ? order.milestonesData
    : Array.from({ length: order.totalMilestones || 4 }, (_, i) => ({ name: `階段 ${i + 1}`, completed: i < order.milestones }));
  const amountPer = Math.round(order.amount / rawMs.length);
  const milestones = rawMs.map((m, i) => {
    const done = m.completed;
    const next = !done && rawMs.slice(0, i).every(prev => prev.completed);
    return {
      idx: i + 1,
      label: m.name || `階段 ${i + 1}`,
      amount: amountPer,
      status: done ? "released" : next ? "in_progress" : "pending",
      releasedAt: null,
    };
  });
  return (
    <div>
      <Card padding={0}>
        {milestones.map((m, i) => (
          <div key={i} style={{
            display: "grid", gridTemplateColumns: "44px 1fr auto auto",
            gap: 14, padding: "16px 18px", alignItems: "center",
            borderBottom: i < milestones.length - 1 ? "1px solid var(--border)" : "none",
          }}>
            <div style={{
              width: 32, height: 32, borderRadius: 999,
              background: m.status === "released" ? "var(--success-soft)" : m.status === "in_progress" ? "var(--accent-soft)" : "var(--surface-2)",
              color: m.status === "released" ? "var(--success)" : m.status === "in_progress" ? "var(--accent)" : "var(--ink-4)",
              display: "flex", alignItems: "center", justifyContent: "center", fontWeight: 600, fontSize: 13,
            }}>
              {m.status === "released" ? <Icon name="check" size={16}/> : m.idx}
            </div>
            <div>
              <div style={{ fontSize: 14, fontWeight: 500 }}>階段 {m.idx} · {m.label}</div>
              <div style={{ fontSize: 11.5, color: "var(--ink-3)", marginTop: 3 }}>
                {m.status === "released" && <>已撥付 · {m.releasedAt}</>}
                {m.status === "in_progress" && <>進行中 · 創作者已提交,等待業主確認</>}
                {m.status === "pending" && <>尚未開始</>}
              </div>
            </div>
            <div className="mono" style={{ fontSize: 14, fontWeight: 500 }}>NT$ {fmtNum(m.amount)}</div>
            <Badge tone={m.status === "released" ? "success" : m.status === "in_progress" ? "accent" : "default"} size="sm" dot>
              {m.status === "released" ? "已撥款" : m.status === "in_progress" ? "審核中" : "待交付"}
            </Badge>
          </div>
        ))}
      </Card>
    </div>
  );
};

const ChatTab = ({ order }) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!order._rawId) { setLoading(false); return; }
    fetch(`/api/admin/orders/${order._rawId}/messages`)
      .then(r => r.ok ? r.json() : null)
      .then(d => setData(d))
      .catch(() => {})
      .finally(() => setLoading(false));
  }, [order._rawId]);

  const conv = data?.conversation;
  const msgs = data?.messages ?? [];

  return (
    <Card padding={0} style={{ overflow: "hidden" }}>
      <div style={{ padding: "10px 14px", borderBottom: "1px solid var(--border)", background: "var(--surface-2)", display: "flex", alignItems: "center", gap: 8, fontSize: 12, color: "var(--ink-3)" }}>
        <Icon name="info" size={13}/> 站內訊息紀錄 · 僅管理員可見 · 平台保留 180 天
        {conv && <span style={{ marginLeft: "auto" }}>{msgs.length} 則訊息</span>}
      </div>
      {loading && (
        <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)" }}>載入中…</div>
      )}
      {!loading && !conv && (
        <div style={{ padding: 32, textAlign: "center", color: "var(--ink-4)", fontSize: 13 }}>此訂單尚無對話紀錄</div>
      )}
      {!loading && conv && msgs.length === 0 && (
        <div style={{ padding: 32, textAlign: "center", color: "var(--ink-4)", fontSize: 13 }}>對話紀錄為空</div>
      )}
      {!loading && conv && msgs.length > 0 && (
        <div style={{ padding: "16px 14px", display: "flex", flexDirection: "column", gap: 12, maxHeight: 500, overflow: "auto" }}>
          {msgs.map((m, i) => {
            const isArtist = m.senderId === conv.artistId;
            const isSystem = m.type === "system";
            if (isSystem) {
              return (
                <div key={m.id} style={{ alignSelf: "center", fontSize: 11.5, color: "var(--ink-3)", padding: "4px 10px", background: "var(--surface-2)", borderRadius: 999 }}>
                  <Icon name="info" size={11} style={{ verticalAlign: -1, marginRight: 4 }}/>{m.content}
                </div>
              );
            }
            const name = isArtist ? conv.artistName : conv.commissionerName;
            const avatarUrl = isArtist ? conv.artistAvatar : conv.commissionerAvatar;
            const role = isArtist ? "創作者" : "委託人";
            const time = m.createdAt ? m.createdAt.slice(0, 16).replace("T", " ") : "";
            return (
              <div key={m.id} style={{ display: "flex", gap: 8, flexDirection: isArtist ? "row" : "row-reverse" }}>
                {avatarUrl && !avatarUrl.includes("avatar-default")
                  ? <img src={avatarUrl} style={{ width: 28, height: 28, borderRadius: "50%", objectFit: "cover", flexShrink: 0, alignSelf: "flex-end" }}/>
                  : <Avatar hue={isArtist ? 200 : 30} glyph={name?.[0] ?? "?"} size={28}/>
                }
                <div style={{ maxWidth: "70%" }}>
                  <div style={{ fontSize: 11, color: "var(--ink-3)", marginBottom: 3, textAlign: isArtist ? "left" : "right" }}>
                    {name} · {role}{time && <span style={{ marginLeft: 6 }}>{time}</span>}
                  </div>
                  {m.type === "image" ? (
                    <div style={{ padding: "10px 12px", background: isArtist ? "var(--surface-2)" : "var(--accent-soft)", borderRadius: 10, display: "flex", gap: 10, alignItems: "center" }}>
                      <img src={m.content} alt="圖片" style={{ width: 80, height: 80, borderRadius: 6, objectFit: "cover" }} onError={e => { e.target.style.display = "none"; }}/>
                    </div>
                  ) : (
                    <div style={{
                      padding: "8px 12px",
                      background: isArtist ? "var(--surface-2)" : "var(--ink)",
                      color: isArtist ? "var(--ink)" : "#fff",
                      borderRadius: 10, fontSize: 13.5, lineHeight: 1.55, whiteSpace: "pre-wrap", wordBreak: "break-word",
                    }}>{m.content}</div>
                  )}
                </div>
              </div>
            );
          })}
        </div>
      )}
    </Card>
  );
};

const FilesTab = ({ order }) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!order._rawId) { setLoading(false); return; }
    fetch(`/api/admin/orders/${order._rawId}`)
      .then(r => r.ok ? r.json() : null)
      .then(d => setData(d))
      .catch(() => {})
      .finally(() => setLoading(false));
  }, [order._rawId]);

  const files = data?.files ?? [];

  return (
    <Card padding={0}>
      <div style={{ padding: "10px 14px", borderBottom: "1px solid var(--border)", background: "var(--surface-2)", display: "flex", alignItems: "center", gap: 8, fontSize: 12, color: "var(--ink-3)" }}>
        <Icon name="shield" size={13}/> 所有檔案已加密儲存 · 下載會記錄至審計日誌
        {!loading && <span style={{ marginLeft: "auto" }}>{files.length} 個檔案</span>}
      </div>
      {loading && <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)" }}>載入中…</div>}
      {!loading && files.length === 0 && (
        <div style={{ padding: 32, textAlign: "center", color: "var(--ink-4)", fontSize: 13 }}>此訂單尚無上傳檔案</div>
      )}
      {!loading && files.length > 0 && (
        <div style={{ padding: 14, display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))", gap: 10 }}>
          {files.map((f, i) => {
            const isImage = /\.(png|jpg|jpeg|gif|webp)$/i.test(f.name ?? "");
            const hue = (i * 47 + 180) % 360;
            return (
              <div key={f.id ?? i} style={{ border: "1px solid var(--border)", borderRadius: 10, overflow: "hidden" }}>
                <div style={{
                  aspectRatio: "4/3", position: "relative", overflow: "hidden",
                  background: isImage && f.url ? "#000" : `linear-gradient(135deg, oklch(82% 0.10 ${hue}), oklch(68% 0.14 ${(hue + 40) % 360}))`,
                  display: "flex", alignItems: "center", justifyContent: "center",
                  color: "rgba(255,255,255,0.7)",
                }}>
                  {isImage && f.url
                    ? <img src={f.url} alt={f.name} style={{ width: "100%", height: "100%", objectFit: "cover" }} onError={e => { e.target.style.display = "none"; }}/>
                    : <Icon name="palette" size={30}/>}
                  <Badge tone="accent" size="sm" style={{ position: "absolute", top: 8, left: 8 }}>創作者</Badge>
                </div>
                <div style={{ padding: "10px 12px" }}>
                  <div style={{ fontSize: 12.5, fontWeight: 500, wordBreak: "break-all", lineHeight: 1.35 }}>{f.name ?? "未命名檔案"}</div>
                  <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 4 }}>{f.milestone ?? "—"}</div>
                  {f.uploadedAt && <div className="mono" style={{ fontSize: 10.5, color: "var(--ink-4)", marginTop: 2 }}>{f.uploadedAt.slice(0, 16).replace("T", " ")}</div>}
                  <div style={{ display: "flex", gap: 4, marginTop: 8 }}>
                    {f.url && <Button size="sm" variant="ghost" icon="eye" style={{ flex: 1 }} onClick={() => window.open(f.url, "_blank")}>預覽</Button>}
                    {f.url && <Button size="sm" variant="ghost" icon="download" style={{ flex: 1 }} onClick={() => { const a = document.createElement("a"); a.href = f.url; a.download = f.name ?? "file"; a.click(); }}>下載</Button>}
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </Card>
  );
};

const PaymentTab = ({ order }) => {
  const released = Math.round(order.amount * (order.milestones / order.totalMilestones));
  const heldInEscrow = order.amount - released;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
      <Card padding={18}>
        <SectionLabel style={{ marginBottom: 12 }}>金額拆解</SectionLabel>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 16 }}>
          {[
            { label: "業主支付", value: order.amount },
            { label: "平台抽成 (15%)", value: order.platformFee, tone: "accent" },
            { label: "創作者分潤 (85%)", value: order.artistPayout, tone: "success" },
          ].map(m => (
            <div key={m.label}>
              <div style={{ fontSize: 11.5, color: "var(--ink-3)" }}>{m.label}</div>
              <div className="mono" style={{ fontSize: 18, fontWeight: 500, marginTop: 2, color: m.tone ? `var(--${m.tone})` : "var(--ink)" }}>NT$ {fmtNum(m.value)}</div>
            </div>
          ))}
        </div>
      </Card>

      <Card padding={18}>
        <SectionLabel style={{ marginBottom: 12 }}>託管款項狀態</SectionLabel>
        <div style={{ display: "flex", gap: 14 }}>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 11.5, color: "var(--ink-3)" }}>已撥付創作者</div>
            <div className="mono" style={{ fontSize: 22, fontWeight: 500, color: "var(--success)" }}>NT$ {fmtNum(Math.round(released * 0.85))}</div>
            <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>{order.milestones}/{order.totalMilestones} 階段</div>
          </div>
          <div style={{ width: 1, background: "var(--border)" }}/>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 11.5, color: "var(--ink-3)" }}>託管中</div>
            <div className="mono" style={{ fontSize: 22, fontWeight: 500, color: "var(--warn)" }}>NT$ {fmtNum(Math.round(heldInEscrow * 0.85))}</div>
            <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>等待下階段交付</div>
          </div>
          <div style={{ width: 1, background: "var(--border)" }}/>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 11.5, color: "var(--ink-3)" }}>平台已結算</div>
            <div className="mono" style={{ fontSize: 22, fontWeight: 500, color: "var(--accent)" }}>NT$ {fmtNum(Math.round(released * 0.15))}</div>
            <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>抽成進入平台帳戶</div>
          </div>
        </div>
      </Card>

      <Card padding={18}>
        <SectionLabel style={{ marginBottom: 12 }}>金流紀錄</SectionLabel>
        <div style={{ fontSize: 13, color: "var(--ink-2)" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "10px 0" }}>
            <Icon name="download" size={15} style={{ color: "var(--success)" }}/>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 13 }}>業主付款託管</div>
              <div className="mono" style={{ fontSize: 11, color: "var(--ink-3)" }}>{order.createdAt}</div>
            </div>
            <span className="mono" style={{ fontSize: 13, fontWeight: 500, color: "var(--success)" }}>+ NT$ {fmtNum(order.amount)}</span>
          </div>
          {order.milestones > 0 && Array.from({ length: order.milestones }, (_, i) => (
            <div key={i} style={{ display: "flex", alignItems: "center", gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)" }}>
              <Icon name="external" size={15} style={{ color: "var(--accent)" }}/>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13 }}>
                  {(Array.isArray(order.milestonesData) && order.milestonesData[i]?.name) || `階段 ${i + 1}`} 撥款給創作者
                </div>
              </div>
              <span className="mono" style={{ fontSize: 13, fontWeight: 500 }}>
                − NT$ {fmtNum(Math.round(order.artistPayout / (order.totalMilestones || 1)))}
              </span>
            </div>
          ))}
        </div>
      </Card>
    </div>
  );
};

const DisputeTab = ({ order }) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!order._rawId) { setLoading(false); return; }
    fetch(`/api/admin/orders/${order._rawId}`)
      .then(r => r.ok ? r.json() : null)
      .then(d => setData(d))
      .catch(() => {})
      .finally(() => setLoading(false));
  }, [order._rawId]);

  if (loading) return <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)" }}>載入中…</div>;

  const artistFiles = (data?.files ?? []);
  const refImages = (data?.refImages ?? []);
  const refText = data?.refText;

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
      {/* Dispute status banner */}
      <Card padding={16} style={{ borderColor: "var(--danger)", borderWidth: 1, borderStyle: "solid", background: "var(--danger-soft)" }}>
        <div style={{ display: "flex", gap: 10, alignItems: "flex-start" }}>
          <Icon name="alert" size={18} style={{ color: "var(--danger)", marginTop: 2 }}/>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 13.5, fontWeight: 600, color: "var(--danger)" }}>調解處理中</div>
            <div style={{ fontSize: 12.5, color: "var(--ink-2)", marginTop: 4, lineHeight: 1.6 }}>
              此訂單已進入調解狀態。以下顯示委託方的需求說明及創作者的上傳檔案，供管理員審查。
            </div>
          </div>
        </div>
      </Card>

      {/* Commissioner's reference info */}
      <div>
        <SectionLabel>委託方需求說明（業主提供）</SectionLabel>
        <Card padding={16}>
          {refText ? (
            <div style={{ fontSize: 13.5, lineHeight: 1.7, color: "var(--ink-2)", whiteSpace: "pre-wrap" }}>{refText}</div>
          ) : (
            <div style={{ fontSize: 13, color: "var(--ink-4)", fontStyle: "italic" }}>無文字說明</div>
          )}
          {refImages.length > 0 && (
            <div style={{ marginTop: 12 }}>
              <div style={{ fontSize: 11.5, color: "var(--ink-3)", marginBottom: 8 }}>參考圖（{refImages.length} 張）</div>
              <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
                {refImages.map((src, i) => (
                  <div key={i} style={{
                    width: 90, height: 90, borderRadius: 8, overflow: "hidden",
                    background: "var(--surface-2)", border: "1px solid var(--border)", flexShrink: 0,
                  }}>
                    <img src={src} alt={`參考圖 ${i + 1}`} style={{ width: "100%", height: "100%", objectFit: "cover" }}
                      onError={e => { e.target.style.display = "none"; }}
                    />
                  </div>
                ))}
              </div>
            </div>
          )}
          {!refText && refImages.length === 0 && (
            <div style={{ fontSize: 12.5, color: "var(--ink-4)", fontStyle: "italic", marginTop: 4 }}>業主未提供參考資料</div>
          )}
        </Card>
      </div>

      {/* Artist-uploaded files */}
      <div>
        <SectionLabel>創作者上傳檔案（{artistFiles.length} 個）</SectionLabel>
        {artistFiles.length === 0 ? (
          <Card padding={16}>
            <div style={{ fontSize: 13, color: "var(--ink-4)", fontStyle: "italic" }}>創作者尚未上傳任何稿件</div>
          </Card>
        ) : (
          <Card padding={0}>
            <div style={{ padding: 14, display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))", gap: 10 }}>
              {artistFiles.map((f, i) => {
                const isImage = /\.(png|jpg|jpeg|gif|webp)$/i.test(f.name ?? "");
                const hue = (i * 47 + 180) % 360;
                return (
                  <div key={f.id ?? i} style={{ border: "1px solid var(--border)", borderRadius: 10, overflow: "hidden" }}>
                    <div style={{
                      aspectRatio: "4/3", position: "relative", overflow: "hidden",
                      background: isImage ? "#000" : `linear-gradient(135deg, oklch(82% 0.10 ${hue}), oklch(68% 0.14 ${(hue + 40) % 360}))`,
                      display: "flex", alignItems: "center", justifyContent: "center",
                      color: "rgba(255,255,255,0.7)",
                    }}>
                      {isImage && f.url ? (
                        <img src={f.url} alt={f.name} style={{ width: "100%", height: "100%", objectFit: "cover" }}
                          onError={e => { e.target.style.display = "none"; }}
                        />
                      ) : (
                        <Icon name="palette" size={30}/>
                      )}
                      <Badge tone="accent" size="sm" style={{ position: "absolute", top: 8, left: 8 }}>創作者</Badge>
                    </div>
                    <div style={{ padding: "10px 12px" }}>
                      <div style={{ fontSize: 12.5, fontWeight: 500, wordBreak: "break-all", lineHeight: 1.35 }}>{f.name}</div>
                      <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 4 }}>{f.milestone ?? "—"}</div>
                      {f.uploadedAt && (
                        <div className="mono" style={{ fontSize: 10.5, color: "var(--ink-4)", marginTop: 2 }}>
                          {f.uploadedAt.slice(0, 16).replace("T", " ")}
                        </div>
                      )}
                      <div style={{ display: "flex", gap: 4, marginTop: 8 }}>
                        {f.url && <Button size="sm" variant="ghost" icon="eye" style={{ flex: 1 }} onClick={() => window.open(f.url, "_blank")}>預覽</Button>}
                        {f.url && <Button size="sm" variant="ghost" icon="download" style={{ flex: 1 }} onClick={() => { const a = document.createElement("a"); a.href = f.url; a.download = f.name ?? "file"; a.click(); }}>下載</Button>}
                      </div>
                    </div>
                  </div>
                );
              })}
            </div>
          </Card>
        )}
      </div>
    </div>
  );
};

// ============== Shared bits ==============

const SectionLabel = ({ children, style }) => (
  <div style={{ fontSize: 11.5, fontWeight: 600, color: "var(--ink-3)", letterSpacing: 0.8, textTransform: "uppercase", marginBottom: 10, ...style }}>{children}</div>
);

const PartyCard = ({ role, user, roleColor }) => {
  const avatarUrl = user?.avatar?.url && !user.avatar.url.includes("avatar-default") ? user.avatar.url : null;
  return (
    <Card padding={14}>
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        {avatarUrl
          ? <img src={avatarUrl} style={{ width: 36, height: 36, borderRadius: "50%", objectFit: "cover", flexShrink: 0 }}/>
          : <Avatar hue={user?.avatar?.hue || 200} glyph={user?.avatar?.glyph || "?"} size={36}/>
        }
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
            <Badge tone={roleColor} size="sm">{role}</Badge>
            {user?.level && <span style={{ fontSize: 11, color: "var(--ink-3)" }}>{user.level}</span>}
          </div>
          <div style={{ fontSize: 13.5, fontWeight: 500, marginTop: 3 }}>{user?.name}</div>
          {user?.email && <div style={{ fontSize: 11, color: "var(--ink-3)" }}>{user.email}</div>}
        </div>
        <Button size="sm" variant="ghost">查看</Button>
      </div>
    </Card>
  );
};

// ============== Action dialogs ==============

const OrderActionDialog = ({ kind, order, onClose, onConfirm }) => {
  const cfg = {
    force_complete: {
      title: `強制結案 · ${order.id}`,
      description: <>
        平台將繞過業主驗收,<b>直接釋出全部託管款項</b>給創作者,並結束此訂單。
        通常用於業主失聯或惡意拖延驗收的情況。
        <div style={{ marginTop: 10, padding: "8px 12px", background: "var(--warn-soft)", borderRadius: 6, fontSize: 12 }}>
          將撥付 <b className="mono">NT$ {fmtNum(order.artistPayout)}</b> 給創作者 {order.artistName}
        </div>
      </>,
      variant: "warn",
      icon: "check",
      confirmText: "強制結案",
      requireReason: true,
      reasonLabel: "強制結案原因",
      reasonPlaceholder: "例:業主驗收期限已過 7 日未回應,且交付內容符合需求。",
      requireOtp: true,
    },
    full_refund: {
      title: `全額退款 · ${order.id}`,
      description: <>
        將 <b className="mono">NT$ {fmtNum(order.amount)}</b> 全額退回業主信用卡。
        平台抽成同步退回,創作者若已收階段款將從下期結算扣除。
        <div style={{ marginTop: 10, padding: "8px 12px", background: "var(--danger-soft)", borderRadius: 6, fontSize: 12, color: "var(--ink-2)" }}>
          ⚠ 創作者 {order.artistName} 本月結算將扣除 NT$ {fmtNum(Math.round(order.artistPayout * (order.milestones / order.totalMilestones)))}
        </div>
      </>,
      variant: "danger",
      icon: "refresh",
      confirmText: "確認全額退款",
      requireReason: true,
      reasonLabel: "退款理由 (會寄給雙方)",
      reasonPlaceholder: "例:經審核,創作者交付品質明顯不符合合約描述,判定業主申訴成立。",
      requireOtp: true,
      requireText: order.id,
    },
    partial_refund: {
      title: `部分退款 · ${order.id}`,
      description: <>指定退款金額,剩餘款項按原分潤比例繼續結算。常用於<b>品質瑕疵但部分可用</b>的狀況。</>,
      variant: "warn",
      icon: "refresh",
      confirmText: "送出退款",
      requireReason: true,
      reasonLabel: "退款理由",
      reasonPlaceholder: "例:交付 3 張但僅 2 張符合需求,退款 1/3 金額作為補償。",
      extraField: {
        label: `退款金額 (最高 NT$ ${fmtNum(order.amount)})`,
        type: "text",
        placeholder: `介於 1 - ${order.amount}`,
        defaultValue: String(Math.round(order.amount / 3)),
      },
      requireOtp: true,
    },
  };
  const c = cfg[kind];
  return (
    <ConfirmDialog
      open
      onClose={onClose}
      onConfirm={onConfirm}
      title={c.title}
      description={c.description}
      variant={c.variant}
      icon={c.icon}
      confirmText={c.confirmText}
      requireReason={c.requireReason}
      reasonLabel={c.reasonLabel}
      reasonPlaceholder={c.reasonPlaceholder}
      extraField={c.extraField}
      requireOtp={c.requireOtp}
      requireText={c.requireText}
    />
  );
};

Object.assign(window, { OrdersPage, MilestonesTab, ChatTab, FilesTab, DisputeTab });
