/* ZY console — 采购建议中心（Procurement COO）。真实字段 + 受控动作四闸门。 */
const DSPROC = window.ZYDesignSystem_d746df;

const RISK_META = {
  negative_stock: { label: "负库存", tone: "danger", icon: "TrendingDown" },
  low_stock: { label: "低库存", tone: "warn", icon: "PackageMinus" },
  human_request: { label: "人工请求", tone: "accent", icon: "Hand" },
};
const POSTATUS_META = {
  buy: { label: "建议下单", tone: "good" },
  deferred_insufficient_funds: { label: "暂缓·资金不足", tone: "neutral" },
  funding_unknown: { label: "成本未知·待人工", tone: "warn" },
  ready_for_review: { label: "待审", tone: "neutral" },
};
const HINT_LABEL = {
  recommended_action_from_history: "历史处理",
  supplier_reliability: "供应商",
  restock_preference_hint: "补货偏好",
};
// 采购反馈动作集（contract: hermes-feedback-ui-contract.md · kind 照表）
const PROC_FB_OPTS = [
  { kind: "not_needed", effect: "suppression", label: "这个先别采购" },
  { kind: "ordered", effect: "resolution", label: "已下单 / 已处理" },
  { kind: "supplier", effect: "supplier", label: "这家供应商不靠谱 / 靠谱" },
  { kind: "preference", effect: "preference", label: "补货偏好（如“每次补到 X”）" },
  { kind: "note", effect: "knowledge", label: "记一笔（其它）" },
];

function KitProcurement() {
  const { Card, SectionHead, Pill, Icon, Button } = DSPROC;
  const K = window.KIT;
  const D = K.procDigest, RQ = D.review_queue, RC = D.recos;

  const SIM_BUDGET = 6000;
  const [simFunds, setSimFunds] = React.useState(false);
  const [showAll, setShowAll] = React.useState(false);
  const [po, setPo] = React.useState(null);        // reco in PO flow
  const [fb, setFb] = React.useState(null);        // reco in hermes feedback
  const [feedback, setFeedback] = React.useState({}); // reco.id -> { kind, effect, text, label }（乐观态：明日生效）
  const [restored, setRestored] = React.useState({}); // suppressed sku_id -> 已恢复（reject 该模式）
  const [ordered, setOrdered] = React.useState({});       // id -> purchase_order_ref

  const assessed = simFunds;
  const items = RC.items;
  let budget = SIM_BUDGET;
  const withStatus = items.map(r => {
    if (!assessed) return { ...r, _status: "ready_for_review" };
    if (r.unit_cost == null) return { ...r, _status: "funding_unknown" };
    if (r.suggested_qty <= 0) return { ...r, _status: "ready_for_review" };
    const line = r.suggested_qty * r.unit_cost;
    if (budget - line >= 0) { budget -= line; return { ...r, _status: "buy", _line: line }; }
    return { ...r, _status: "deferred_insufficient_funds", _line: line };
  });
  const buyCount = assessed ? withStatus.filter(r => r._status === "buy").length : RC.buy_count;
  const buySum = withStatus.filter(r => r._status === "buy").reduce((s, r) => s + (r._line || 0), 0);
  const negN = items.filter(r => r.risk === "negative_stock").length;
  // 已被学习抑制：读模型 suppressed[]（去掉已恢复）+ 本次反馈乐观抑制（明日生效）
  const LEARN = D.learning_applied || {};
  const rmSupp = (RC.suppressed || []).filter(s => !restored[s.sku_id]);
  const optimisticSupp = Object.entries(feedback)
    .filter(([id, f]) => f.effect === "suppression")
    .map(([id, f]) => { const r = items.find(x => x.id === id) || {}; return { id, sku_id: r.sku_id, sku_name: r.sku_name, supplier_ref: r.supplier_ref, risk_category: r.risk, suppressed_reason: f.text || f.label, pending: true }; });
  const suppList = [...optimisticSupp, ...rmSupp];
  const suppN = suppList.length;

  const CAP = 5;
  const shown = showAll ? withStatus : withStatus.slice(0, CAP);

  const tpl = "1.7fr 0.9fr 0.85fr 0.7fr 0.7fr 0.8fr 1.25fr 1fr 1.15fr";

  const canGen = (r) => r.suggested_qty > 0 && !!r.supplier_ref;
  const genReason = (r) => !r.supplier_ref ? "未配供应商" : r.suggested_qty <= 0 ? "无建议量" : "";

  const PAYTERMS = ["现结", "预付30%", "货到付款", "月结30天", "月结60天", "月结90天"];
  const SUPPLIERS = (window.KIT.suppliers || []);
  const supName = (ref) => { const s = SUPPLIERS.find(x => x.ref === ref); return s ? s.name : ""; };
  const poFlowFor = (r) => {
    const supOpts = [{ value: "", label: "— 未选择供应商 —" }, ...SUPPLIERS.map(s => ({ value: s.ref, label: s.name + " · " + s.ref }))];
    return {
      icon: "PackagePlus", title: "生成采购单",
      subject: r.sku_id + " · " + (r.supplier_name || "未配供应商"),
      fields: [
        { key: "qty", label: "采购数量", type: "number", unit: "件", value: r.suggested_qty },
        { key: "supplierRef", label: "供应商", type: "select", options: supOpts, value: r.supplier_ref || "" },
        { key: "term", label: "账期", type: "select", options: PAYTERMS, value: r.payment_term || "现结" },
        { key: "unitCost", label: "采购价", type: "number", unit: "元/件", value: r.unit_cost != null ? r.unit_cost : "" },
      ],
      blocked: (v, f) => !(f.supplierRef && f.supplierRef.toString().trim()) || !(Number(f.qty) > 0),
      blockedReason: (v, f) => !(f.supplierRef && f.supplierRef.toString().trim())
        ? "未选择供应商。建议来自历史，可改、可不采纳；但写采购单必须有供应商映射。"
        : "采购数量需大于 0。建议量仅作参考，请按实际填写。",
      previewBanner: "建议来自历史口径 · 采购价随原材料波动，可改后再预览（dry-run，不写 JST）",
      previewRows: (v, f) => {
        const qty = Number(f.qty) || 0;
        const uc = f.unitCost === "" || f.unitCost == null ? null : Number(f.unitCost);
        const goods = uc != null ? uc * qty : null;
        const changed = qty !== r.suggested_qty || (f.supplierRef || "") !== (r.supplier_ref || "") || (f.term || "") !== (r.payment_term || "")
          || (uc != null && uc !== r.unit_cost);
        return [
          { k: "采购范围 scope", v: "owned_warehouse_procurement" },
          { k: "供应商", v: (supName(f.supplierRef) || "—") + " · " + (f.supplierRef || "未配") },
          { k: "账期", v: f.term || "未知" },
          { k: "单品明细", v: r.sku_id + " × " + qty + " 件 @ " + (uc != null ? window.yuan(uc) : "待核价") },
          { k: "预估总成本", v: goods != null ? window.yuan(goods) : "待核价（采购价未填）", tone: goods == null ? "warn" : "" },
          { k: "对比建议", v: changed ? "已偏离系统建议（按你的填写执行）" : "与系统建议一致", tone: changed ? "warn" : "good" },
        ];
      },
      payload: (v, f) => ({ action: "create_purchase_order", scope: "owned_warehouse_procurement",
        supplier_ref: (f.supplierRef || "").toString().trim(), supplier_name: supName(f.supplierRef), payment_term: f.term,
        unit_cost: f.unitCost === "" || f.unitCost == null ? null : Number(f.unitCost),
        items: [{ sku_id: r.sku_id, qty: Number(f.qty) || 0 }] }),
      approveNote: "引擎在缺少 decision_ref 时拒绝执行；下方为本次审批的决策引用。",
      refPrefix: "PO-JST", executeLabel: "创建采购单（写 JST）",
      receiptRows: (ref, v, f) => {
        const qty = Number(f.qty) || 0;
        const uc = f.unitCost === "" || f.unitCost == null ? null : Number(f.unitCost);
        const total = uc != null ? uc * qty : null;
        return [
          { k: "purchase_order_ref", v: ref },
          { k: "供应商 · 账期", v: (supName(f.supplierRef) || "—") + " · " + (f.term || "—") },
          { k: "采购数量 · 采购价", v: qty + " 件 @ " + (uc != null ? window.yuan(uc) : "待核价") },
          { k: "预估总成本", v: total != null ? window.yuan(total) : "待核价（采购价未填）" },
          { k: "write_status", v: "confirmed", tone: "good" },
          { k: "回读校验", v: "已回读 · 单据存在", tone: "good" },
        ];
      },
      voidLabel: "作废采购单",
    };
  };

  // 提交反馈 = 已审批（POST /internal/procurement-coo/hermes/feedback）· 乐观态：明日生效
  const fbPayload = (r) => (opt, text) => ({
    sku_id: r.sku_id, supplier_ref: r.supplier_ref || null, risk_category: r.risk,
    kind: opt.kind, text: text || "", decision: "approve",
  });
  const submitFeedback = (r, opt, text) => {
    // POST fbPayload(r)(opt, text) -> { ok, entry } （后端 Phase D 按契约建）
    setFeedback(m => ({ ...m, [r.id]: { kind: opt.kind, effect: opt.effect, text, label: opt.label } }));
    setFb(null);
  };
  const undoFeedback = (id) => setFeedback(m => { const n = { ...m }; delete n[id]; return n; });
  const restoreSupp = (sku_id) => setRestored(s => ({ ...s, [sku_id]: true }));

  return (
    <div className="view viewfade">
      <Card className="ovstrip">
        <div className="ovstrip__head">
          <span className="ovstrip__orb"><Icon name="PackageSearch" size={20} /></span>
          <div className="ovstrip__id">
            <div className="ovstrip__title">采购日报 · Procurement COO<span className="ovstrip__mode"><span className="ovstrip__dot" />读优先 · 人在环</span></div>
            <div className="ovstrip__judge">每日一份高信号摘要 · 待审采购范围 + 建议补货（祝余文化本仓）· 审批前不写 JST</div>
          </div>
          <div className="ovstrip__src">
            <span className="ovstrip__srclabel">数据源</span>
            <span className="ovstrip__srcval">采购日报读模型</span>
            <Pill tone="good" soft>{D.read_only ? "只读" : "可写"}</Pill>
          </div>
        </div>
        <div className="pqhead">
          <Icon name="Newspaper" size={16} />
          <span className="pqhead__t">{D.headline}</span>
          <span className="pqhead__at"><Icon name="Clock" size={12} />生成于 {D.generated_at}</span>
        </div>
      </Card>

      <div className="kpigrid">
        <Card className="kpi kpi--feat" hover><div className="kpi__top"><span className="kpi__label">待审采购范围</span><Pill tone="warn" soft>需复核</Pill></div>
          <div className="kpi__val num">{RQ.entry_count}</div><div className="kpi__hint">按 scope 分组 · 仅复核入口</div></Card>
        <Card className="kpi" hover><div className="kpi__top"><span className="kpi__label">建议补货</span><Icon name="PackagePlus" size={15} style={{ color: "var(--fg-3)" }} /></div>
          <div className="kpi__val num">{RC.total}</div><div className="kpi__hint">已预排序 · 负库存优先</div></Card>
        <Card className="kpi" hover><div className="kpi__top"><span className="kpi__label">可买项</span><Pill tone={assessed ? "good" : "neutral"} soft>{assessed ? "资金已评估" : "资金未评估"}</Pill></div>
          <div className={"kpi__val num" + (assessed && buyCount ? " ovstat--good" : "")}>{buyCount}</div><div className="kpi__hint">{assessed ? "在可用资金内 · " + window.yuan(buySum) : "回款数据待店铺 COO"}</div></Card>
        <Card className="kpi" hover><div className="kpi__top"><span className="kpi__label">负库存项</span><Icon name="TrendingDown" size={15} style={{ color: "var(--negative)" }} /></div>
          <div className={"kpi__val num" + (negN ? " ovstat--danger" : "")}>{negN}</div><div className="kpi__hint">最急 · 当前库存为负</div></Card>
      </div>

      {/* 待审采购队列 · 按 scope 分组 */}
      <Card>
        <SectionHead title="待审采购队列" icon="ClipboardList" sub="按采购范围（scope）分组 · 仅复核入口，不在此写入"
          right={<Pill tone="neutral" soft>{RQ.entry_count} 范围</Pill>} />
        <div className="rvqgrid">
          {RQ.entries.map((e, i) => (
            <div className="rvqcard" key={i}>
              <div className="rvqcard__top">
                <span className="rvqcard__name">{e.scope_display_name}</span>
                <span className="rvqcard__n num">{e.source_count}<span className="rvqcard__nu">单</span></span>
              </div>
              <div className="rvqcard__scope num">{e.procurement_scope}</div>
              <div className="rvqcounts">
                {Object.entries(e.status_counts || {}).map(([k, v]) => (
                  <span className={"rvqchip rvqchip--" + k.toLowerCase()} key={k}>{k}<b className="num">{v}</b></span>
                ))}
              </div>
            </div>
          ))}
        </div>
      </Card>

      {/* 建议补货 */}
      <Card>
        <SectionHead title="建议补货" icon="PackagePlus" sub="祝余文化本仓 · 已按风险与动销预排序 · 生成采购单为唯一写动作（需老板审批）"
          right={<div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
            <span className="hlearn" title="applyProcurementLearning · active_memory_total"><Icon name="Sparkles" size={12} />Hermes 已学会 {LEARN.active_memory_total || 0} 条</span>
            <span className="pqsim"><span className="pqsim__l">资金维度</span>
              <button className={"pqsim__b" + (!simFunds ? " is-on" : "")} onClick={() => setSimFunds(false)}>未评估</button>
              <button className={"pqsim__b" + (simFunds ? " is-on" : "")} onClick={() => setSimFunds(true)}>模拟已评估</button>
            </span>
          </div>} />

        {assessed ? (
          <div className="pqfunds pqfunds--on">
            <Icon name="Wallet" size={14} />
            <span>模拟资金评估 · 预算 {window.yuan(SIM_BUDGET)} · 已分配 {window.yuan(buySum)}（{buyCount} 项建议下单），其余按排序暂缓</span>
            <span className="pqfundbar"><span className="pqfundbar__fill" style={{ width: Math.min(100, Math.round(buySum / SIM_BUDGET * 100)) + "%" }} /></span>
          </div>
        ) : (
          <div className="pqfunds">
            <Icon name="Info" size={14} />
            <span>资金维度未启用（cash_assessed = false）· 回款数据待店铺 COO 同步，暂不渲染资金分配；可切「模拟已评估」预览资金排序效果。</span>
          </div>
        )}

        <div className="dtscroll">
          <div className="dt" style={{ minWidth: 1080 }}>
            <div className="dt__head" style={{ gridTemplateColumns: tpl }}>
              <span>SKU</span><span>风险</span><span>当前 / 安全</span><span>近期销量</span><span>建议量</span><span>单位成本</span><span>供应商 · 账期</span><span>状态</span><span style={{ textAlign: "right" }}>操作</span>
            </div>
            {shown.map(r => {
              const rm = RISK_META[r.risk] || {};
              const sm = POSTATUS_META[r._status] || {};
              const hintKeys = Object.keys(r.hints || {});
              const poRef = ordered[r.id];
              const fbState = feedback[r.id];
              const fbCtl = fbState
                ? <span className="fbdone" title={fbState.text || fbState.label}><Icon name="Sparkles" size={12} />已反馈·明日生效<button className="fbdone__u" onClick={() => undoFeedback(r.id)}>撤销</button></span>
                : <Button variant="ghost" size="sm" onClick={() => setFb(r)}>反馈</Button>;
              return (
                <div className={"dt__row" + (r.risk === "negative_stock" ? " is-bad" : "")} style={{ gridTemplateColumns: tpl }} key={r.id}>
                  <span className="dt__name">
                    <b>{r.sku_name}{r.human_requested && <span className="pqbadge">人工请求</span>}</b>
                    <span className="dt__sub num">{r.sku_id}</span>
                    {hintKeys.length > 0 && <span className="pqhint"><Icon name="Sparkles" size={11} />{hintKeys.map(k => HINT_LABEL[k] + "：" + r.hints[k]).join(" · ")}</span>}
                  </span>
                  <span><Pill tone={rm.tone} soft>{rm.label}</Pill></span>
                  <span className="num"><b className={r.qty < 0 ? "ovstat--danger" : ""}>{r.qty}</b><span className="pqmuted"> / {r.min_qty == null ? "未设" : r.min_qty}</span></span>
                  <span className={"num" + (r.recent_sales === 0 ? " pqmuted" : "")}>{r.recent_sales}</span>
                  <span className="num">{r.suggested_qty > 0 ? "+" + r.suggested_qty : "—"}</span>
                  <span className="num">{r.unit_cost == null ? <span className="pqmuted">未知</span> : window.yuan(r.unit_cost)}</span>
                  <span className="dt__name">
                    {r.supplier_ref ? <><b style={{ fontWeight: 600, fontSize: 12.5 }}>{r.supplier_name}</b><span className="dt__sub num">{r.supplier_ref} · {r.payment_term || "账期未知"}</span></>
                      : <span className="pqmuted" style={{ color: "var(--negative)" }}>未配供应商</span>}
                  </span>
                  <span><Pill tone={sm.tone} soft>{sm.label}</Pill></span>
                  <span style={{ textAlign: "right" }}>
                    {poRef
                      ? <span style={{ display: "inline-flex", gap: 6, justifyContent: "flex-end", alignItems: "center" }}>
                          {fbCtl}
                          <Pill tone="good" soft>已生成</Pill>
                          <Button variant="ghost" size="sm" onClick={() => setPo(r)}>回执</Button>
                        </span>
                      : canGen(r)
                        ? <span style={{ display: "inline-flex", gap: 6, justifyContent: "flex-end", alignItems: "center" }}>
                            {fbCtl}
                            <Button variant="solid" size="sm" onClick={() => setPo(r)}>生成采购单</Button>
                          </span>
                        : <span style={{ display: "inline-flex", gap: 6, justifyContent: "flex-end", alignItems: "center" }}>
                            {fbCtl}
                            {!r.supplier_ref
                              ? <Button variant="ghost" size="sm" onClick={() => setPo(r)}>补供应商并生成</Button>
                              : <span className="pqmuted" title="不满足生成条件">{genReason(r)}</span>}
                          </span>}
                  </span>
                </div>
              );
            })}
          </div>
        </div>
        <div className="pqfoot">
          <span className="pqfoot__l"><Icon name="ShieldCheck" size={13} />JST 为唯一事实源 · 摘要只读 · 仅老板审批的单张采购单可写；抑制 {suppN} 项</span>
          {withStatus.length > CAP && <button className="pqmore" onClick={() => setShowAll(v => !v)}>{showAll ? "收起" : "查看全部 " + withStatus.length + " 项"}<Icon name={showAll ? "ChevronUp" : "ChevronDown"} size={14} /></button>}
        </div>
      </Card>

      {/* 已被学习抑制 suppressed[]（折叠 · 可恢复） */}
      {suppList.length > 0 && (
        <Card>
          <SectionHead title="已被学习抑制" icon="BellOff" sub="反馈让 COO 明日不再推送这些项 · 没有静默消失，随时可恢复"
            right={<Pill tone="neutral" soft>{suppList.length} 项</Pill>} />
          <div className="hsupp">
            {suppList.map((s, i) => (
              <div className="hsupp__row" key={s.suppressed_by_memory || s.id || i}>
                <span className={"hsupp__ic" + (s.pending ? " hsupp__ic--pend" : "")}><Icon name="BellOff" size={14} /></span>
                <div className="hsupp__b">
                  <div className="hsupp__t">{s.sku_name || "—"} <span className="num">{s.sku_id}</span>{s.pending && <span className="hsupp__pend">明日生效</span>}</div>
                  <div className="hsupp__why">{s.suppressed_reason}{s.suppressed_by_memory && <span className="hsupp__mem num"> · {s.suppressed_by_memory}</span>}</div>
                </div>
                {s.pending
                  ? <Button variant="ghost" size="sm" onClick={() => undoFeedback(s.id)}>撤销</Button>
                  : <Button variant="ghost" size="sm" onClick={() => restoreSupp(s.sku_id)}>恢复 / 不再抑制</Button>}
              </div>
            ))}
          </div>
        </Card>
      )}

      {po && <window.KitGatedWrite flow={poFlowFor(po)} existingRef={ordered[po.id]} onClose={() => setPo(null)}
        onExecuted={(ref) => setOrdered(o => ({ ...o, [po.id]: ref }))}
        onVoided={() => { setOrdered(o => { const n = { ...o }; delete n[po.id]; return n; }); setPo(null); }} />}
      {fb && <window.KitHermesFeedback item={fb} title="Hermes 反馈 · 采购建议" endpoint="/internal/procurement-coo/hermes/feedback" options={PROC_FB_OPTS} payloadFor={fbPayload(fb)} onClose={() => setFb(null)} onSubmit={submitFeedback} />}
    </div>
  );
}

function KitCost({ onAct }) {
  const { Card, SectionHead, Pill, Button, Donut, Icon } = DSPROC;
  const K = window.KIT, S = window.KitStrip, Kp = window.KitKpi;
  const total = 142, covered = 135;
  const coverage = Math.round((covered / total) * 100);
  const tpl = "1.4fr 0.9fr 0.9fr 1.4fr 0.9fr";
  const fillCost = (r) => onAct({
    title: "补录 SKU 成本", subject: r.sku + " · " + r.name, phrase: "确认补成本", submitLabel: "确认补录成本", source: "sku_cost",
    preflight: "只写入该 SKU 成本字段并回算受影响订单，不改其它成本。",
    editFields: r.fields,
    derive: (e) => {
      const cost = (r.fields || []).reduce((s, f) => s + (Number(e[f.key]) || 0), 0);
      const profit = r.price - cost;
      const margin = r.price ? Math.round((profit / r.price) * 1000) / 10 : 0;
      return [
        { k: "近30天均价", v: window.yuan(r.price) },
        { k: "补录后单位成本", v: window.yuan(cost) },
        { k: "单位毛利", v: window.yuan(profit), tone: profit < 0 ? "ovstat--danger" : "ovstat--good" },
        { k: "毛利率", v: margin + "%", tone: margin < 0 ? "ovstat--danger" : margin < 20 ? "ovstat--warn" : "ovstat--good" },
      ];
    },
    preview: [{ k: "缺失字段", v: r.missing }, { k: "影响范围", v: "近 30 天 " + r.sold30 + " 单将按新成本回算" }],
    wont: ["不会自动改其它成本", "不会自动下采购单", "不会写财务"], forbidden: ["POST /api/cost/update", "POST /ops/sku-cost/set"], rollbackNote: "补录后进重算队列，重算前可撤销",
  });
  return (
    <div className="view viewfade">
      <S icon="ReceiptText" title="成本管理 / 补成本" mode="采购监督" judge="缺成本 SKU 清单 · 工厂价 / 采购价 / 运费价 · 补成本后触发订单回算" src="SKU 成本主数据" />
      <div className="kpigrid">
        <Kp label="缺成本 SKU" value={K.costMissing.length} hint="无法核算利润" pill="需补录" pillTone="danger" feat valTone="ovstat--danger" />
        <Kp label="成本条目总数" value={total} hint="SKU 成本主数据" icon="ReceiptText" />
        <Kp label="活跃 SKU" value={covered} hint="已补成本" valTone="good" />
        <Card className="kpi" style={{ flexDirection: "row", alignItems: "center", justifyContent: "space-between" }}>
          <div><div className="kpi__label" style={{ marginBottom: 8 }}>成本覆盖率</div><div className="kpi__hint">已补 / 全部</div></div>
          <Donut value={coverage} sub="覆盖" />
        </Card>
      </div>
      <Card>
        <SectionHead title="缺成本 SKU" icon="CircleAlert" sub="补成本走受控动作，写入后回算受影响订单" />
        <div className="dtscroll"><div className="dt" style={{ minWidth: 680 }}>
          <div className="dt__head" style={{ gridTemplateColumns: tpl }}><span>SKU</span><span>仓库</span><span>近30天销量</span><span>缺失字段</span><span></span></div>
          {K.costMissing.map(r => (
            <div className="dt__row" style={{ gridTemplateColumns: tpl }} key={r.sku}>
              <span className="dt__name"><b>{r.sku}</b><span className="dt__sub">{r.name}</span></span>
              <span className="dt__sub2">{r.wh}</span>
              <span className="num">{r.sold30}</span>
              <span className="dt__sub2" style={{ color: "var(--negative)" }}>{r.missing}</span>
              <span style={{ textAlign: "right" }}><Button variant="solid" size="sm" onClick={() => fillCost(r)}>补成本</Button></span>
            </div>
          ))}
        </div></div>
      </Card>
    </div>
  );
}

Object.assign(window, { KitProcurement, KitCost });
