// Shared severity + status vocabulary. Single source of truth for the SEV1-4
// rubric, the hard-coded SEV -> Jira priority map, the friendly customer-facing
// status map, and the ETA cadence. Loaded early; everything hangs off window.NS.
//
// Design rule (from the research): the CUSTOMER never sees a SEV code — they see
// plain language ("logged as high-impact"). SEV codes + Jira priorities are the
// vendor-side abstraction, shown only on the triage board.

(function () {
  // impact x urgency rubric. `code` is internal, `label` is customer-facing.
  const SEVERITY = {
    SEV1: {
      code: "SEV1", rank: 1, label: "Critical", customer: "critical impact",
      emoji: "🔴", jiraPriority: "Highest", etaMinutes: 30,
      rubric: "Outage, data loss, or security exposure. Everyone or a whole workflow is blocked.",
    },
    SEV2: {
      code: "SEV2", rank: 2, label: "High", customer: "high impact",
      emoji: "🟠", jiraPriority: "High", etaMinutes: 120,
      rubric: "A major feature is broken with no good workaround. Significant blast radius.",
    },
    SEV3: {
      code: "SEV3", rank: 3, label: "Medium", customer: "moderate impact",
      emoji: "🟡", jiraPriority: "Medium", etaMinutes: 60 * 8,
      rubric: "Degraded or partly broken, but a workaround exists. Limited blast radius.",
    },
    SEV4: {
      code: "SEV4", rank: 4, label: "Low", customer: "minor impact",
      emoji: "⚪", jiraPriority: "Low", etaMinutes: 60 * 48,
      rubric: "Minor or cosmetic. Nice to fix; nobody is blocked.",
    },
  };

  const SEV_ORDER = ["SEV1", "SEV2", "SEV3", "SEV4"];

  function sev(code) {
    return SEVERITY[String(code || "").toUpperCase()] || SEVERITY.SEV3;
  }

  // Friendly, calm status the customer sees, mapped from the live Jira status
  // category. Jira statuses vary per project, so we key off the status
  // *category* (To Do / In Progress / Done) which is stable.
  function friendlyStatus(jiraCategory, jiraName) {
    const c = String(jiraCategory || "").toLowerCase();
    if (c.includes("done") || c.includes("complete")) {
      return { key: "resolved", label: "Resolved", cls: "status-resolved",
               blurb: "Fixed and shipped — here's what we did." };
    }
    if (c.includes("progress") || c.includes("indeterminate")) {
      return { key: "progress", label: "Being worked on", cls: "status-progress",
               blurb: "Our team has picked this up." };
    }
    return { key: "logged", label: "Logged", cls: "status-logged",
             blurb: "We've received it and triaged the severity." };
  }

  // next-update contract: severity sets how soon we promise to check back.
  function nextUpdateLabel(sevCode) {
    const m = sev(sevCode).etaMinutes;
    if (m <= 30) return "within 30 min";
    if (m < 60 * 4) return `within ${Math.round(m / 60)} h`;
    if (m < 60 * 24) return "within the day";
    return `within ${Math.round(m / 60 / 24)} days`;
  }

  // The bug schema the intake agent must fill. `key` matches the tool schema in
  // api/support-agent.js; `required` fields gate ticket creation, the rest are
  // best-effort. Used by the chat's progress rail AND the confirm card.
  const SCHEMA_FIELDS = [
    { key: "title", label: "Summary", required: true },
    { key: "reproSteps", label: "Steps to reproduce", required: true },
    { key: "expected", label: "Expected", required: true },
    { key: "actual", label: "Actual", required: true },
    { key: "component", label: "Area / feature", required: false },
    { key: "environment", label: "Environment", required: false },
    { key: "errorText", label: "Error / console", required: false },
    { key: "blastRadius", label: "Who's affected", required: false },
    { key: "firstSeen", label: "First seen", required: false },
  ];

  function kbVerdictLabel(v) {
    return v === "known-issue" ? "Known issue"
      : v === "works-as-designed" ? "Working as designed"
      : v === "answered" ? "Answered from the KB"
      : "Knowledge-base match";
  }

  // ---- Normalization -------------------------------------------------------
  // Tickets arrive from three places (local mirror, POST response, live Jira
  // read) with slightly different shapes. Everything that renders a ticket goes
  // through this first, so the customer and admin views show the SAME structure
  // for every ticket, whatever its origin.
  const STATUS_CATEGORIES = ["To Do", "In Progress", "Done"];

  function normalizeTicket(raw) {
    const t = raw || {};
    const draft = t.draft || {};
    const statusCategory = STATUS_CATEGORIES.indexOf(t.statusCategory) >= 0 ? t.statusCategory : "To Do";
    const created = num(t.createdAt) || Date.now();
    const updated = num(t.updatedAt) || created;
    return {
      key: t.key || "—",
      url: t.url || null,
      live: !!t.live,
      title: t.title || "(untitled)",
      severity: sev(t.severity).code,
      statusCategory,
      status: t.status || statusCategory,
      component: t.component || draft.component || "",
      account: t.account || "",
      reporter: t.reporter || "",
      createdAt: created,
      updatedAt: updated,
      kbVerdict: t.kbVerdict || draft.kbVerdict || "",
      kbCitation: t.kbCitation || draft.kbCitation || "",
      // detail fields — present for locally-filed tickets, blank for Jira reads
      reproSteps: t.reproSteps || draft.reproSteps || "",
      expected: t.expected || draft.expected || "",
      actual: t.actual || draft.actual || "",
      environment: t.environment || draft.environment || "",
      errorText: t.errorText || draft.errorText || "",
      blastRadius: t.blastRadius || draft.blastRadius || "",
      severityRationale: t.severityRationale || draft.severityRationale || "",
    };
  }

  // A ticket's lifecycle as an ordered, uniform event list. Jira gives us only
  // created/updated + the current category, so we derive the milestones we can
  // prove and mark the rest as pending — the same shape for every ticket.
  function buildHistory(t) {
    const n = normalizeTicket(t);
    const s = sev(n.severity);
    const cat = n.statusCategory;
    const reached = (c) => STATUS_CATEGORIES.indexOf(cat) >= STATUS_CATEGORIES.indexOf(c);

    const events = [
      { key: "reported", label: "Reported", at: n.createdAt, done: true,
        detail: n.reporter ? `by ${n.reporter}` : "via the support agent" },
      { key: "triaged", label: "Triaged", at: n.createdAt, done: true,
        detail: `Graded ${s.label.toLowerCase()} impact · ${s.jiraPriority} priority` },
      { key: "progress", label: "Being worked on", at: reached("In Progress") ? n.updatedAt : null,
        done: reached("In Progress"), detail: reached("In Progress") ? "Picked up by the team" : "Waiting for the team to pick it up" },
      { key: "resolved", label: "Resolved", at: cat === "Done" ? n.updatedAt : null,
        done: cat === "Done", detail: cat === "Done" ? "Fixed and shipped" : `Next update ${nextUpdateLabel(n.severity)}` },
    ];
    return events;
  }

  function num(v) { const n = Number(v); return isFinite(n) && n > 0 ? n : 0; }

  window.NS = Object.assign(window.NS || {}, {
    SEVERITY, SEV_ORDER, sev, friendlyStatus, nextUpdateLabel, SCHEMA_FIELDS, kbVerdictLabel,
    normalizeTicket, buildHistory, STATUS_CATEGORIES,
  });
})();
