// ai-core.jsx — AI logic: risk scoring, reply composer, NL search, insights, escalation
// Pure functions + data only (no JSX). Loaded after data.jsx/auth.jsx.

/* ---------- per-order AI signals (drive risk scoring + sentiment) ---------- */
const AI_SIGNALS = {
  "TRP-48201": { vip: false, sentiment: "neutral",  repeat: false, channelPref: "whatsapp" },
  "TRP-48197": { vip: false, sentiment: "negative", repeat: true,  channelPref: "whatsapp" }, // messaged twice
  "TRP-48188": { vip: false, sentiment: "neutral",  repeat: false, channelPref: "email" },
  "TRP-48176": { vip: false, sentiment: "neutral",  repeat: false, channelPref: "whatsapp" },
  "TRP-48170": { vip: true,  sentiment: "neutral",  repeat: true,  channelPref: "email" },    // repeat buyer, 4 orders
  "TRP-48155": { vip: false, sentiment: "neutral",  repeat: false, channelPref: "email" },
  "TRP-48142": { vip: false, sentiment: "neutral",  repeat: false, channelPref: "whatsapp" },
  "TRP-48131": { vip: false, sentiment: "negative", repeat: false, channelPref: "whatsapp" }, // wrong fitment
  "TRP-48120": { vip: false, sentiment: "neutral",  repeat: false, channelPref: "whatsapp" },
  "TRP-48098": { vip: false, sentiment: "neutral",  repeat: false, channelPref: "whatsapp" },
  "TRP-48077": { vip: true,  sentiment: "negative", repeat: false, channelPref: "email" },    // escalated on social
  "TRP-48054": { vip: false, sentiment: "neutral",  repeat: false, channelPref: "email" },
  "TRP-48039": { vip: false, sentiment: "neutral",  repeat: false, channelPref: "whatsapp" },
  "TRP-48012": { vip: true,  sentiment: "neutral",  repeat: false, channelPref: "email" },    // RM689 BMW premium
  "TRP-47998": { vip: false, sentiment: "neutral",  repeat: false, channelPref: "whatsapp" },
  "TRP-47981": { vip: false, sentiment: "neutral",  repeat: false, channelPref: "whatsapp" },
};
function signalsFor(id) { return AI_SIGNALS[id] || { vip: false, sentiment: "neutral", repeat: false, channelPref: "whatsapp" }; }

/* ---------- risk scoring ---------- */
// Returns { score (0-100), band, reasons:[{key,label,detail,weight}] }
function riskScore(row) {
  const s = signalsFor(row.id);
  const reasons = [];
  if (s.vip) reasons.push({ key: "vip", label: "VIP customer", detail: "Priority account · loyalty tier", weight: 24, icon: "shieldcheck" });
  if (row.value >= 400) reasons.push({ key: "value", label: "High order value", detail: "RM " + row.value.toLocaleString(), weight: 20, icon: "card" });
  if (row.waitH >= 48) reasons.push({ key: "wait", label: "Long waiting time", detail: fmtWait(row.waitH) + " · past 48h SLA", weight: 26, icon: "clock" });
  else if (row.waitH >= 24) reasons.push({ key: "wait", label: "Extended wait", detail: fmtWait(row.waitH) + " elapsed", weight: 13, icon: "clock" });
  if (s.sentiment === "negative") reasons.push({ key: "sentiment", label: "Negative sentiment detected", detail: "Frustration in recent messages", weight: 21, icon: "chat" });
  if (s.repeat) reasons.push({ key: "repeat", label: "Repeat complaint", detail: "Customer has contacted before", weight: 17, icon: "refresh" });

  let score = reasons.reduce((a, r) => a + r.weight, 0);
  // small base by issue severity so nothing reads 0
  score += ({ high: 14, medium: 7, low: 3 })[row.priority];
  score = Math.min(99, score);
  const band = score >= 70 ? "critical" : score >= 45 ? "elevated" : "low";
  return { score, band, reasons };
}
const RISK_BAND = {
  critical: { label: "Critical risk", color: "#b91c1c", bg: "#fef2f2", ring: "#fecaca", bar: "#ef4444" },
  elevated: { label: "Elevated risk", color: "#c2410c", bg: "#fff7ed", ring: "#fed7aa", bar: "#f97316" },
  low:      { label: "Low risk",      color: "#3f6212", bg: "#f7fee7", ring: "#d9f99d", bar: "#84cc16" },
};

/* ---------- escalation recommendation ---------- */
const ESCALATION_TARGET = {
  "Unfulfilled Paid Order": "Warehouse Team",
  "Missing Tracking": "Logistics",
  "Warranty Claim": "Warranty Lead",
  "Installation Booking": "Branch Manager",
  "Delayed Shipment": "Warehouse Team",
  "Payment Mismatch": "Finance",
  "Stock Shortage": "Inventory Team",
  "Return/Refund": "CX Lead",
};
function escalationRec(row) {
  const target = ESCALATION_TARGET[row.issue] || "Operations Lead";
  if (row.priority === "high" && row.waitH >= 48)
    return { level: "now", text: `Escalate to ${target} now — SLA breached`, target };
  if (row.priority === "high")
    return { level: "soon", text: `Escalate to ${target} if unresolved within 4h`, target };
  if (signalsFor(row.id).sentiment === "negative")
    return { level: "watch", text: `Monitor — escalate to ${target} if customer follows up`, target };
  return { level: "none", text: "No escalation needed — resolve in queue", target };
}
const ESC_LEVEL = {
  now:   { color: "#b91c1c", bg: "#fef2f2", icon: "escalate" },
  soon:  { color: "#c2410c", bg: "#fff7ed", icon: "clock" },
  watch: { color: "#a16207", bg: "#fefce8", icon: "eye" },
  none:  { color: "#15803d", bg: "#f0fdf4", icon: "check" },
};

/* ---------- next-step (recommended action, short) ---------- */
function nextStep(row) { return row.action; }

/* ---------- multi-channel / multi-tone reply composer ---------- */
const ISSUE_INFO = {
  "Unfulfilled Paid Order": { sit: "your paid order hasn't shipped yet", next: "we're confirming stock and prioritising dispatch", verb: "fulfillment" },
  "Missing Tracking":       { sit: "your tracking details didn't come through", next: "we're retrieving your tracking number now", verb: "tracking" },
  "Warranty Claim":         { sit: "your warranty claim is being reviewed", next: "we're processing your replacement", verb: "warranty" },
  "Installation Booking":   { sit: "your installation slot needs reconfirming", next: "we're securing a new time for you", verb: "installation" },
  "Delayed Shipment":       { sit: "your order is taking longer than usual to ship", next: "we're expediting it with the courier", verb: "dispatch" },
  "Payment Mismatch":       { sit: "there was a small discrepancy on your payment", next: "we're reconciling it now", verb: "payment" },
  "Stock Shortage":         { sit: "the item you ordered is briefly out of stock", next: "we're arranging an alternative or a restock ETA", verb: "stock" },
  "Return/Refund":          { sit: "your return request is being processed", next: "we're arranging your replacement", verb: "return" },
};

const CHANNELS = [
  { key: "whatsapp", label: "WhatsApp", icon: "chat" },
  { key: "email",    label: "Email",    icon: "mail" },
  { key: "internal", label: "Internal", icon: "users" },
];
const TONES = [
  { key: "professional", label: "Professional" },
  { key: "friendly",     label: "Friendly" },
  { key: "apologetic",   label: "Apologetic" },
  { key: "concise",      label: "Concise" },
];

function composeReply(row, channel, tone) {
  const first = (row.customer.name || "there").split(" ")[0];
  const info = ISSUE_INFO[row.issue] || { sit: "there's an update on your order", next: "we're looking into it" };

  if (channel === "internal") {
    const esc = escalationRec(row);
    const r = riskScore(row);
    const urg = tone === "concise" ? "" :
      tone === "apologetic" ? "Apologies for the churn on this one. " :
      tone === "friendly" ? "Quick one for the team — " : "";
    return [
      `🏷  INTERNAL ESCALATION · ${row.id}`,
      `Customer: ${row.customer.name} (${row.car}) · waiting ${fmtWait(row.waitH)}`,
      `Issue: ${row.issue} · Priority ${row.priority.toUpperCase()} · AI risk ${r.score}`,
      ``,
      `${urg}Context: ${row.summary}`,
      `Requested action: ${row.action}`,
      `Recommendation: ${esc.text}.`,
    ].join("\n");
  }

  // openers per tone
  const opener = {
    professional: `Hi ${first}, thank you for getting in touch.`,
    friendly:     `Hi ${first}! Thanks so much for your patience${channel === "whatsapp" ? " 🙂" : "."}`,
    apologetic:   `Hi ${first}, we're really sorry for the inconvenience here.`,
    concise:      `Hi ${first},`,
  }[tone];

  const body = tone === "concise"
    ? `We can see ${info.sit}. ${cap(info.next)}.`
    : `We can see that ${info.sit}, and ${info.next}.`;

  const closer = {
    professional: "We'll follow up with a further update shortly.",
    friendly:     channel === "whatsapp" ? "We'll keep you posted! 🙌" : "We'll keep you posted every step of the way.",
    apologetic:   "Thank you for bearing with us — we'll make this right.",
    concise:      "Update to follow shortly.",
  }[tone];

  if (channel === "whatsapp") {
    return tone === "concise"
      ? `${opener} ${body} ${closer}`
      : `${opener}\n\n${body}\n\n${closer}`;
  }
  // email
  const subject = `Update on your TRAPO order ${row.id}`;
  const sign = tone === "concise" ? "— TRAPO Support" : "Best regards,\nTRAPO Operations Team";
  return `Subject: ${subject}\n\n${opener}\n\n${body}\n\n${closer}\n\n${sign}`;
}
function cap(s) { return s.charAt(0).toUpperCase() + s.slice(1); }

/* ---------- natural-language search ---------- */
const CAR_BRANDS = ["honda", "toyota", "perodua", "proton", "mazda", "bmw", "tesla", "nissan", "mercedes"];
const ISSUE_KEYWORDS = [
  { kw: ["warranty", "claim", "defect"], issue: "Warranty Claim", label: "Warranty claims" },
  { kw: ["tracking", "track", "awb"], issue: "Missing Tracking", label: "Missing tracking" },
  { kw: ["installation", "install", "booking", "slot"], issue: "Installation Booking", label: "Installation booking" },
  { kw: ["payment", "mismatch", "charge"], issue: "Payment Mismatch", label: "Payment mismatch" },
  { kw: ["stock", "out of stock", "shortage"], issue: "Stock Shortage", label: "Stock shortage" },
  { kw: ["return", "refund"], issue: "Return/Refund", label: "Return / refund" },
  { kw: ["unfulfilled", "not fulfilled", "not shipped"], issue: "Unfulfilled Paid Order", label: "Unfulfilled paid orders" },
];

function parseSearch(query) {
  const q = (query || "").toLowerCase().trim();
  const filters = []; // {type,label}
  const tests = [];

  if (!q) return { filters, rows: [] };

  // car brand
  for (const b of CAR_BRANDS) {
    if (q.includes(b)) { filters.push({ type: "brand", label: cap(b), icon: "box" }); tests.push(r => r.car.toLowerCase().includes(b)); break; }
  }
  // issue type
  for (const ik of ISSUE_KEYWORDS) {
    if (ik.kw.some(k => q.includes(k))) { filters.push({ type: "issue", label: ik.label, icon: "alert" }); tests.push(r => r.issue === ik.issue); break; }
  }
  // delayed / late / overdue — broad: waiting past 24h or a delayed/unfulfilled issue
  if (/delayed|delay|\blate\b|overdue|stuck/.test(q)) {
    filters.push({ type: "delayed", label: "Delayed (24h+)", icon: "clock" });
    tests.push(r => r.waitH >= 24 || r.issue === "Delayed Shipment" || r.issue === "Unfulfilled Paid Order");
  }
  // priority
  if (/\bhigh\b/.test(q) && !/high[- ]?value/.test(q)) { filters.push({ type: "priority", label: "High priority", icon: "flag" }); tests.push(r => r.priority === "high"); }
  // high value
  if (/high[- ]?value|expensive|premium/.test(q)) { filters.push({ type: "value", label: "High value (RM400+)", icon: "card" }); tests.push(r => r.value >= 400); }
  // VIP
  if (/\bvip\b|loyal/.test(q)) { filters.push({ type: "vip", label: "VIP customers", icon: "shieldcheck" }); tests.push(r => signalsFor(r.id).vip); }
  // sentiment
  if (/negative|angry|upset|complain/.test(q)) { filters.push({ type: "sentiment", label: "Negative sentiment", icon: "chat" }); tests.push(r => signalsFor(r.id).sentiment === "negative"); }
  // unresolved
  if (/unresolved|open|outstanding|pending/.test(q)) { filters.push({ type: "status", label: "Unresolved", icon: "dot" }); tests.push(r => r.status !== "resolved"); }
  // time threshold: "older than 3 days", "48h", "2 days"
  const dayMatch = q.match(/(\d+)\s*(day|days)/);
  const hourMatch = q.match(/(\d+)\s*(h|hour|hours)/);
  if (dayMatch) { const h = +dayMatch[1] * 24; filters.push({ type: "age", label: `Older than ${dayMatch[1]}d`, icon: "clock" }); tests.push(r => r.waitH >= h); }
  else if (hourMatch) { const h = +hourMatch[1]; filters.push({ type: "age", label: `Older than ${h}h`, icon: "clock" }); tests.push(r => r.waitH >= h); }

  let rows = EXCEPTIONS.slice();
  if (tests.length) rows = rows.filter(r => tests.every(t => t(r)));
  else rows = EXCEPTIONS.filter(r => (r.id + r.customer.name + r.car + r.issue + r.product).toLowerCase().includes(q));

  rows = rows.sort((a, b) => riskScore(b).score - riskScore(a).score);
  return { filters, rows };
}

const SEARCH_EXAMPLES = [
  "Show delayed Honda orders",
  "Unresolved warranty claims older than 3 days",
  "High-value delayed customers",
  "VIP customers with negative sentiment",
];

/* ---------- AI operational insights (dashboard) ---------- */
const INSIGHTS = [
  { id: "in1", icon: "shield", tone: "warn", headline: "Warranty claims up 14% this week", detail: "12 open vs 10.5 weekly avg — driven by HEX II discolouration on batch B-2024-11.", trend: "up", delta: "+14%", action: { label: "Review claims", page: "queue" } },
  { id: "in2", icon: "truck", tone: "warn", headline: "Most delayed warehouse: Klang DC", detail: "Avg dispatch 61h vs 38h network-wide. 3 SLA breaches logged today.", trend: "up", delta: "+23h", action: { label: "View delayed", page: "queue" } },
  { id: "in3", icon: "wrench", tone: "neutral", headline: "Top issue category: Installation scheduling", detail: "31% of today's exceptions. Installer availability tight at Penang branch.", trend: "flat", delta: "31%", action: { label: "See bookings", page: "queue" } },
  { id: "in4", icon: "sparkles", tone: "ok", headline: "AI auto-drafted 23 replies today", detail: "Saving an estimated 4.6 staff-hours. 96% sent without edits.", trend: "down", delta: "−18% effort", action: { label: "View activity", page: "audit" } },
];
const INSIGHT_TONE = {
  warn:    { color: "#c2410c", bg: "#fff7ed", ring: "#fed7aa" },
  ok:      { color: "#15803d", bg: "#f0fdf4", ring: "#bbf7d0" },
  neutral: { color: "#4338ca", bg: "#eef2ff", ring: "#c7d2fe" },
};

Object.assign(window, {
  AI_SIGNALS, signalsFor, riskScore, RISK_BAND, escalationRec, ESC_LEVEL, nextStep,
  CHANNELS, TONES, composeReply, parseSearch, SEARCH_EXAMPLES, INSIGHTS, INSIGHT_TONE,
});
