/* ZY console — 销售 · ZY COO 二级：投流 ROI / 客户私域 / 转化漏斗 / 订单审核。
   （素材工厂已提升为独立 COO 工作台，见 MaterialFactory.jsx。） */
const DSSALES = window.ZYDesignSystem_d746df;

function KitAds({ focus }) {
  const { Card, SectionHead, Pill, Icon, Segmented } = DSSALES;
  const K = window.KIT, S = window.KitStrip, Kp = window.KitKpi;
  const PLAT_AD = { "1688": "1688", pdd: "拼多多", jx: "京喜", intl: "国际站", tiktokshop: "TikTok Shop" };
  const focusName = focus ? PLAT_AD[focus] : null;
  const chans = focus ? K.adChannels.filter(c => c.plat === focus) : K.adChannels;
  const PERIOD_AD = { "日": { mult: 1, scope: "今日" }, "周": { mult: 6.4, scope: "本周" }, "月": { mult: 25.8, scope: "本月" } };
  const [period, setPeriod] = React.useState("日");
  const pm = PERIOD_AD[period];
  const sc = v => Math.round(v * pm.mult);
  const spend = sc(chans.reduce((s, c) => s + c.spend, 0));
  const gmv = sc(chans.reduce((s, c) => s + c.gmv, 0));
  const profit = sc(chans.reduce((s, c) => s + c.profit, 0));
  const neg = chans.filter(c => c.profit < 0).length;
  const TONE = { "正常": "good", "需关注": "warn", "负毛利": "danger" };
  const tpl = "1.5fr 1.2fr 0.8fr 1fr 1fr 0.8fr";
  return (
    <div className="view viewfade">
      <div className="periodbar">
        <span className="periodbar__l"><Icon name="CalendarRange" size={15} />数据口径</span>
        <Segmented options={["日", "周", "月"]} value={period} onChange={setPeriod} />
      </div>
      <S icon="Megaphone" title={focusName ? focusName + " · 投流 ROI" : "投流 · ROI"} mode="投流监督" judge={focusName ? "平台投流 COO · " + focusName + " · " + chans.length + " 个投放渠道 · 负毛利渠道优先复核" : "各渠道投放花费、ROAS 与广告利润 · 每渠道一名投流 COO · 负毛利渠道优先复核"} src="投流数据 · 广告报表读模型" />
      <div className="kpigrid">
        <Kp label="投放花费" value={window.yuan(spend)} hint={pm.scope + "·" + (focusName || "全渠道")} icon="Wallet" />
        <Kp label="加权 ROAS" value={(gmv / spend).toFixed(1) + "x"} hint="GMV / 花费" feat />
        <Kp label="广告利润" value={window.yuan(profit)} hint={"老板口径 · " + pm.scope} valTone="good" />
        <Kp label="负毛利渠道" value={neg} hint="需暂停 / 复核" pill={neg ? "优先" : "正常"} pillTone={neg ? "danger" : "good"} valTone={neg ? "ovstat--danger" : ""} />
      </div>
      <Card>
        <SectionHead title="渠道明细" icon="Megaphone" sub={"口径：" + pm.scope + " · 负毛利渠道建议暂停投流并复核成本口径"} />
        <div className="dtscroll"><div className="dt" style={{ minWidth: 760 }}>
          <div className="dt__head" style={{ gridTemplateColumns: tpl }}><span>渠道</span><span>投流 COO</span><span>花费</span><span>ROAS</span><span>GMV</span><span>状态</span></div>
          {chans.map(c => (
            <div className="dt__row" style={{ gridTemplateColumns: tpl }} key={c.id}>
              <span className="dt__name"><b>{c.name}</b><span className="dt__sub">广告利润 {window.yuan(sc(c.profit))}</span></span>
              <span className="dt__sub2">{c.coo}</span>
              <span className="num">{window.yuan(sc(c.spend))}</span>
              <span className={"num" + (c.roas < 2 ? " ovstat--danger" : c.roas < 3 ? " ovstat--warn" : "")}>{c.roas}x</span>
              <span className="num">{window.yuan(sc(c.gmv))}</span>
              <span><Pill tone={TONE[c.status]} soft>{c.status}</Pill></span>
            </div>
          ))}
        </div></div>
      </Card>
    </div>
  );
}

function KitCrm({ onAct }) {
  const { Card, SectionHead, Pill, Button, Icon } = DSSALES;
  const K = window.KIT, S = window.KitStrip, Kp = window.KitKpi, MaskedId = window.KitMaskedIdentity;
  const TIER = { VIP: "accent", 复购: "good", 新客: "neutral" };
  const tplC = "1.3fr 0.6fr 0.8fr 0.9fr 0.6fr";
  const [q, setQ] = React.useState("");
  const query = q.trim().toLowerCase();
  const custList = query
    ? K.customers.filter(c => c.name.toLowerCase().includes(query) || (c.tier || "").toLowerCase().includes(query))
    : K.customers;
  const confirmBind = (b) => onAct({
    title: "确认客户绑定", subject: (b.name || "未知客户") + " ↔ 1688 订单 " + (b.raw || "—"), phrase: "确认绑定", submitLabel: "确认该绑定建议", source: "企微客户读模型",
    preflight: "只核对该 1688 客户业务员是否已加进企微（考核项），不写企微、不写尘锋。",
    preview: [{ k: "对应 1688 订单", v: b.raw || "—" }, { k: "匹配方式", v: b.confidence != null ? "自动匹配 " + Math.round(b.confidence * 100) + "%" : "人工核对（无自动置信）" }, { k: "绑定状态", from: b.status, to: "已绑定" }],
    wont: ["不会自动绑定客户", "不会写企微", "不会写尘锋"], forbidden: ["未登录提交", "非白名单接口"], rollbackNote: "绑定后可在客户详情解绑",
  });
  return (
    <div className="view viewfade">
      <S icon="Users" title="客户 · 私域" mode="客户监督" judge="企微 + 尘锋 + 聚水潭客户闭环 · 客户排行 / 漏斗 / 绑定待处理" src="企微客户数据 + 客户转化漏斗" />
      <div className="kpigrid">
        <Kp label="1688 新客户" value={(K.funnel[0] ? K.funnel[0].n : 0).toLocaleString("zh-CN")} hint="本期发现" icon="Users" />
        <Kp label="企微已绑定" value={(K.funnel[1] ? K.funnel[1].n : 0).toLocaleString("zh-CN")} hint="业务员已加企微" feat valTone="good" />
        <Kp label="产生 MZ 订单" value={K.funnel[2] ? K.funnel[2].n : 0} hint="绑定后成单" />
        <Kp label="待绑定核对" value={K.bindings.length} hint="业务员是否已加企微 · 考核项" pill="需人工" pillTone="warn" />
      </div>
      <div className="ovgrid ovgrid--2">
        <Card>
          <SectionHead title="客户排行" icon="Crown" sub="累计金额 · 首次/最近下单"
            right={<div className="tblsearch">
              <Icon name="Search" size={14} />
              <input className="tblsearch__in" value={q} onChange={e => setQ(e.target.value)} placeholder="搜客户 · 姓名 / 层级" />
              {q && <button className="tblsearch__x" onClick={() => setQ("")} title="清除"><Icon name="X" size={13} /></button>}
            </div>} />
          <div className="dtscroll"><div className="dt" style={{ minWidth: 480 }}>
            <div className="dt__head" style={{ gridTemplateColumns: tplC }}><span>客户</span><span>订单</span><span>累计</span><span>最近下单</span><span>层级</span></div>
            {custList.map((c, i) => (
              <div className="dt__row" style={{ gridTemplateColumns: tplC }} key={c.name}>
                <span className="dt__item"><MaskedId name={c.name} /></span>
                <span className="num">{c.orders}</span><span className="num">{window.yuan(c.amount)}</span>
                <span className="dt__sub2 num">{c.last}</span><span><Pill tone={TIER[c.tier]} soft>{c.tier}</Pill></span>
              </div>
            ))}
            {custList.length === 0 && <div className="emptyrow"><Icon name="SearchX" size={14} />无匹配「{q}」的客户</div>}
          </div></div>
          {query && custList.length > 0 && <div className="tblsearch__count">匹配 <b className="num">{custList.length}</b> / {K.customers.length} 位客户</div>}
        </Card>
        <Card>
          <SectionHead title="客户绑定待核对" icon="Link" sub="考核：该 1688 客户业务员是否已加进企微 · 对应哪个 1688 订单 · 受控动作确认" right={<Pill tone="warn" soft>{K.bindings.length} 待核对</Pill>} />
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {K.bindings.map((b, i) => (
              <div key={i} style={{ border: "1px solid var(--border)", borderRadius: 12, padding: "12px 13px" }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 10 }}>
                  <div style={{ minWidth: 0 }}>
                    <div style={{ fontSize: 13, fontWeight: 600 }}>
                      {b.lowConfidence ? "未知客户 · 待人工核对" : <span>{b.name}（企微）↔ 1688 订单 <span className="num">{b.raw}</span></span>}
                    </div>
                    <div style={{ fontSize: 11.5, color: "var(--fg-3)" }}>
                      {b.confidence != null
                        ? <span className="num">匹配置信 {Math.round(b.confidence * 100)}%</span>
                        : "无自动匹配 · 需人工核对业务员是否已加企微"}
                    </div>
                  </div>
                  {b.lowConfidence
                    ? <Pill tone="neutral">低置信 · 需人工</Pill>
                    : <Button variant="solid" size="sm" onClick={() => confirmBind(b)}>确认绑定</Button>}
                </div>
              </div>
            ))}
          </div>
        </Card>
      </div>
    </div>
  );
}

/* 稳定的字符串→色相 hash：按 review_type 派生一个稳定的强调色，
   不写死"曼芝/大熊"两色——花名册可增可减，第 N 个业务员也要有自己的颜色。 */
function hashHue(str) {
  let h = 0;
  const s = String(str || "");
  for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) >>> 0;
  return h % 360;
}

const MZ_REVIEW_STATUS_LABEL = { pending: "待审核", yes: "已通过", no: "已拒绝" };
/* 与 Orders.jsx 的 RV_TONE 同一套三态语义（待审核/已通过/已拒绝→warn/good/danger）；
   两文件各自走独立 <script> 标签加载，此处按同一映射复刻一份常量，避免跨文件耦合。 */
const MZ_TONE = { "待审核": "warn", "已通过": "good", "已拒绝": "danger" };

function KitMzReview({ onAct }) {
  const { Card, SectionHead, Pill, Button, Icon } = DSSALES;
  const K = window.KIT, S = window.KitStrip, Kp = window.KitKpi;
  const roster = K.salespeople || [];
  const rows = K.mzReviews || [];

  // 按当月评审数据里实际出现的 review_type 动态分列；栏头用花名册 display_name，
  // 查不到花名册条目（未来可能有新业务员未及时补花名册）时兜底显示 review_type 本身，
  // 而不是假设只有曼芝/大熊两列。
  const types = Array.from(new Set(rows.map(r => r.review_type)));
  const rosterById = {};
  roster.forEach(p => { rosterById[p.salesperson_id] = p; });

  const pendingTotal = rows.filter(r => r.review_status === "pending").length;
  const passedTotal = rows.filter(r => r.review_status === "yes").length;
  const rejectedTotal = rows.filter(r => r.review_status === "no").length;
  const commissionTotal = rows.reduce((sum, r) => sum + (r.review_status === "no" ? 0 : (r.commission || 0)), 0);

  const doReview = (row, action) => {
    const person = rosterById[row.review_type];
    const label = person ? person.display_name : row.review_type;
    const toYes = action === "yes";
    onAct({
      title: toYes ? "确认订单审核通过" : "拒绝订单审核",
      subject: (label || "待审") + " · " + row.internal_order_no,
      phrase: toYes ? "确认通过" : "确认拒绝",
      submitLabel: toYes ? "确认通过" : "确认拒绝",
      danger: !toYes,
      source: "订单审核队列 · MZ 审核",
      preflight: "只标记该单审核状态为通过/拒绝，不自动重算月度、不自动发起退款。",
      preview: [
        { k: "内部单号", v: row.internal_order_no },
        { k: "平台单号", v: row.online_order_no },
        { k: "审核状态", from: MZ_REVIEW_STATUS_LABEL[row.review_status] || row.review_status, to: toYes ? "已通过" : "已拒绝" },
        { k: "提成", from: window.yuan(row.commission), to: toYes ? window.yuan(row.commission) : window.yuan(0) },
      ],
      wont: ["不自动通过审核", "不自动拒绝提成之外还做其他重算", "不自动重算月度"],
      forbidden: ["未登录提交", "非白名单接口"],
      rollbackNote: "审核结果可由老板在时限内改判",
    });
  };

  return (
    <div className="view viewfade">
      <S icon="ClipboardCheck" title="订单审核" mode="审核监督" judge="按业务员动态分列的逐单审核 · 通过 / 拒绝（拒绝或跳过 → 该单提成归 0）" src="订单审核队列 · MZ 审核" />
      <div className="kpigrid">
        <Kp label="待审核" value={pendingTotal} hint="尚未判定" pill={pendingTotal ? "需处理" : "已清空"} pillTone={pendingTotal ? "warn" : "good"} />
        <Kp label="已通过" value={passedTotal} hint="本月累计" valTone="good" />
        <Kp label="已拒绝" value={rejectedTotal} hint="提成已归零" />
        <Kp label="提成合计" value={window.yuan(commissionTotal)} hint="已按拒绝单归零核算" feat />
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))", gap: 14 }}>
        {types.map(t => {
          const person = rosterById[t];
          const displayName = person ? person.display_name : t;
          const hue = hashHue(t);
          const accent = "hsl(" + hue + ", 55%, 45%)";
          const accentSoft = "hsl(" + hue + ", 55%, 95%)";
          const colRows = rows.filter(r => r.review_type === t);
          const pendingN = colRows.filter(r => r.review_status === "pending").length;
          const commissionEligible = person ? !!person.commission_eligible : true;
          return (
            <Card key={t}>
              <SectionHead
                title={displayName + (person && !person.active ? "（已离职）" : "")}
                icon="User"
                sub={colRows.length + " 单 · 待审 " + pendingN}
                right={<span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
                  <span style={{ width: 8, height: 8, borderRadius: "50%", background: accent, display: "inline-block" }} />
                  {person && person.review_pending ? <Pill tone="warn" soft>有待审</Pill> : null}
                </span>}
              />
              <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
                {colRows.map((r, i) => (
                  <div key={r.internal_order_no + i} style={{ border: "1px solid var(--border)", borderRadius: 12, padding: "11px 12px", background: accentSoft }}>
                    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 8 }}>
                      <div style={{ minWidth: 0 }}>
                        <div style={{ fontSize: 12.5, fontWeight: 700 }} className="num">{r.internal_order_no}</div>
                        <div style={{ fontSize: 11.5, color: "var(--fg-3)" }}>{r.shop_name} · {r.online_order_no}</div>
                        <div style={{ fontSize: 11.5, color: "var(--fg-3)" }}>买家：{r.buyer}</div>
                      </div>
                      <Pill tone={MZ_TONE[MZ_REVIEW_STATUS_LABEL[r.review_status]] || "neutral"} soft>{MZ_REVIEW_STATUS_LABEL[r.review_status] || r.review_status}</Pill>
                    </div>
                    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 6, marginTop: 8, fontSize: 11.5 }}>
                      <span>销售额 <b className="num">{window.yuan(r.sales_amount)}</b></span>
                      <span>退款 <b className="num">{window.yuan(r.refund_amount)}</b></span>
                      <span>毛利 <b className="num">{window.yuan(r.gross_margin)}</b></span>
                      <span>支出运费 <b className="num">{window.yuan(r.expense_freight)}</b></span>
                      <span>收入运费 <b className="num">{window.yuan(r.income_freight)}</b></span>
                      <span>快递 <b>{r.courier || "—"}</b></span>
                    </div>
                    {commissionEligible
                      ? <div style={{ marginTop: 8, fontSize: 12 }}>提成 <b className="num" style={{ color: "var(--positive)" }}>{window.yuan(r.commission)}</b></div>
                      : <div style={{ marginTop: 8, fontSize: 12, color: "var(--fg-3)" }}>无提成（{colRows.length} 订单）</div>}
                    {r.mz_note ? <div style={{ marginTop: 6, fontSize: 11.5, color: "var(--fg-3)" }}>备注：{r.mz_note}</div> : null}
                    {r.review_status === "pending" && (
                      <div style={{ display: "flex", gap: 8, marginTop: 10 }}>
                        <Button variant="solid" size="sm" onClick={() => doReview(r, "yes")}>通过</Button>
                        <Button variant="ghost" size="sm" onClick={() => doReview(r, "no")}>拒绝</Button>
                      </div>
                    )}
                  </div>
                ))}
                {colRows.length === 0 && <div className="emptyrow"><Icon name="CircleCheck" size={14} />本月无待审订单</div>}
              </div>
            </Card>
          );
        })}
        {types.length === 0 && (
          <Card><div className="emptyrow"><Icon name="CircleCheck" size={16} />当前没有待审核订单</div></Card>
        )}
      </div>
    </div>
  );
}

function KitFunnel() {
  const { Card, SectionHead } = DSSALES;
  const K = window.KIT, S = window.KitStrip;
  const max = K.funnel[0].n;
  return (
    <div className="view viewfade">
      <S icon="Filter" title="转化漏斗" mode="客户监督" judge="1688 新客户 → 企微绑定/跟进 → 产生曼芝订单 → 审核提成 · 考核每一层流失 · 覆盖全部业务员" src="客户转化漏斗数据（1688→企微绑定 考核口径）" />
      <Card>
        <SectionHead title="转化漏斗" icon="Filter" sub="统计周期：近 30 日" />
        <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
          {K.funnel.map((f, i) => {
            const pct = (f.n / max) * 100;
            const conv = i === 0 ? 100 : (f.n / K.funnel[i - 1].n * 100).toFixed(0);
            return (
              <div key={i} style={{ display: "flex", alignItems: "center", gap: 14 }}>
                <span style={{ width: 96, fontSize: 13, fontWeight: 600, flexShrink: 0 }}>{f.stage}</span>
                <div style={{ flex: 1, height: 30, background: "var(--surface-2)", borderRadius: 8, overflow: "hidden" }}>
                  <div style={{ width: pct + "%", height: "100%", background: "var(--accent)", borderRadius: 8, display: "flex", alignItems: "center", paddingLeft: 11, color: "#fff", fontWeight: 700, fontFamily: "var(--font-num)", fontSize: 13 }}>{f.n.toLocaleString("zh-CN")}</div>
                </div>
                <span style={{ width: 64, textAlign: "right", fontSize: 12, color: "var(--fg-3)" }} className="num">{i === 0 ? "起点" : "↓ " + conv + "%"}</span>
              </div>
            );
          })}
        </div>
      </Card>
    </div>
  );
}

Object.assign(window, { KitAds, KitCrm, KitFunnel, KitMzReview });
