// sla.jsx — SLA system for the Support Center.
//
// Ported from the design handoff (zerov2-design/design_handoff_support_sla).
// Adapted to work against real Flowboard tickets — the design used
// minutes-from-now offsets (`createdAtMin` / `firstReplyAtMin`); we compute
// those from real `created_at` / `first_reply_at` ISO timestamps via
// `_ticketToSlaShape()` so every helper below sees the same canonical shape.
//
// What's hardcoded for now:
//   - Agent roster (SLA_AGENTS) — workspace constant
//   - Plan SLA config (SLA_PLAN_CONFIG) — `pro` / `starter` / `enterprise`
//   - Per-priority coverage (SLA_COVERAGE) — urgent = 24x7, others = business
//   - Business hours + holidays (SLA_BUSINESS_HOURS / SLA_HOLIDAYS)
//   - Per-ticket responder chain — first three agents from SLA_AGENTS
//
// In production, these become workspace settings exposed via the Team &
// SLA tab (see SlaTeamSettings).

// ── Agents (support team) ─────────────────────────────────
const SLA_AGENTS = [
  { id: "ag_priya",  name: "Priya Sharma",  role: "L1 — Tier-1 lead",
    initials: "PS", color: "#0073ea",
    email: "priya@flowboard.app",   whatsapp: "+91 98xxxx2210",
    channels: { email: true,  whatsapp: true  },
    status: "available", hours: null,
    onLeave: [], onCall: ["urgent"] },

  { id: "ag_arjun",  name: "Arjun Mehta",   role: "L2 — Senior",
    initials: "AM", color: "#a25ddc",
    email: "arjun@flowboard.app",   whatsapp: "+91 98xxxx4471",
    channels: { email: true,  whatsapp: true  },
    status: "available", hours: null,
    onLeave: [], onCall: ["urgent"] },

  { id: "ag_jules",  name: "Jules Sato",    role: "L3 — Escalation",
    initials: "JS", color: "#fdab3d",
    email: "jules@flowboard.app",   whatsapp: "+81 90xxxx7733",
    channels: { email: true,  whatsapp: false },
    status: "busy", hours: { start: 12, end: 21, label: "12:00–21:00 JST" },
    onLeave: [], onCall: ["urgent", "high"] },

  { id: "ag_aya",    name: "Aya Okafor",    role: "L1",
    initials: "AY", color: "#00c875",
    email: "aya@flowboard.app",     whatsapp: "+234 80xxxx9911",
    channels: { email: true,  whatsapp: false },
    status: "available", hours: null,
    onLeave: [], onCall: [] },

  { id: "ag_rae",    name: "Rae Park",      role: "L2",
    initials: "RP", color: "#579bfc",
    email: "rae@flowboard.app",     whatsapp: "+1 415xxx5567",
    channels: { email: true,  whatsapp: true  },
    status: "on_leave", hours: null,
    onLeave: [{ from: "May 5", to: "May 12", note: "Vacation — Goa" }],
    onCall: [] },

  { id: "ag_diego",  name: "Diego Alvarez", role: "L3 — Weekends",
    initials: "DA", color: "#e2445c",
    email: "diego@flowboard.app",   whatsapp: "+34 6xxxx2245",
    channels: { email: true,  whatsapp: true  },
    status: "off_duty", hours: { start: 14, end: 23, label: "14:00–23:00 CET" },
    onLeave: [], onCall: ["urgent"] },
];

// ── Plan SLA configs ──────────────────────────────────────
const SLA_PLAN_CONFIG = {
  starter:    { firstReplyMin: 60, reminderMin: 10, severeAtMin: 60, severeReminderMin: 5 },
  pro:        { firstReplyMin: 30, reminderMin: 5,  severeAtMin: 30, severeReminderMin: 2 },
  enterprise: { firstReplyMin: 20, reminderMin: 5,  severeAtMin: 30, severeReminderMin: 2 },
};
const SLA_PLAN_FALLBACK = { firstReplyMin: 60, reminderMin: 15, severeAtMin: 90, severeReminderMin: 10 };

// ── Per-priority coverage rule ────────────────────────────
const SLA_COVERAGE = {
  urgent: { mode: "24x7",     label: "24/7 — server down, prod outages" },
  high:   { mode: "business", label: "Business hours — significant impact" },
  normal: { mode: "business", label: "Business hours — standard" },
  low:    { mode: "business", label: "Business hours — low impact" },
};

// ── Business hours (workspace-wide) ───────────────────────
const SLA_BUSINESS_HOURS = {
  timezone: "Asia/Kolkata",
  start: 9, end: 18,
  weekdays: [1, 2, 3, 4, 5],
};

// ── Indian gazetted holidays (illustrative 2026) ──────────
const SLA_HOLIDAYS = [
  { date: "2026-01-26", label: "Republic Day" },
  { date: "2026-03-04", label: "Holi" },
  { date: "2026-04-03", label: "Good Friday" },
  { date: "2026-05-01", label: "Labour Day" },
  { date: "2026-08-15", label: "Independence Day" },
  { date: "2026-10-02", label: "Gandhi Jayanti" },
  { date: "2026-11-09", label: "Diwali" },
  { date: "2026-12-25", label: "Christmas" },
];

// ── Adapter: real ticket → SLA-shape ticket ───────────────
// The design works in minutes-from-now offsets. Real Flowboard tickets
// carry ISO timestamps. This converts one to the other and fills in
// responder-chain defaults (first three agents) until those become
// per-customer settings.
function _toMinAgo(iso) {
  if (!iso) return null;
  const t = new Date(iso).getTime();
  if (!Number.isFinite(t)) return null;
  return Math.round((t - Date.now()) / 60000); // negative = in the past
}
function _ticketToSlaShape(t, agents) {
  if (!t) return null;
  const list = Array.isArray(agents) && agents.length ? agents : SLA_AGENTS;
  // First agent reply: prefer an explicit ticket.first_reply_at column
  // (added in a future migration), fall back to scanning comments.
  let firstReplyIso = t.first_reply_at || t.firstReplyAt || null;
  if (!firstReplyIso && Array.isArray(t.comments)) {
    const agent = t.comments.find(c => c.author_kind === "agent");
    if (agent) firstReplyIso = agent.created_at;
  }
  // Resolved/closed tickets without a recorded first reply time get
  // treated as "met" by stamping the resolved timestamp — better than
  // showing "breached" forever for a long-closed ticket.
  if (!firstReplyIso && (t.status === "resolved" || t.status === "closed")) {
    firstReplyIso = t.resolved_at || t.updated_at || t.created_at;
  }

  return {
    id: t.id,
    priority: t.priority || "normal",
    status: t.status || "open",
    createdAtMin   : _toMinAgo(t.created_at) ?? 0,
    firstReplyAtMin: _toMinAgo(firstReplyIso),
    // Responder chain — workspace default until per-ticket overrides exist.
    firstResponderId : t.firstResponderId  || (list[0] && list[0].id),
    secondResponderId: t.secondResponderId || (list[1] && list[1].id),
    thirdResponderId : t.thirdResponderId  || (list[2] && list[2].id),
  };
}

// ── Helpers ───────────────────────────────────────────────
function slaPlanFor(customer) {
  if (!customer) return SLA_PLAN_FALLBACK;
  const planId = customer.planId || customer.plan_id || (customer.plan && customer.plan.id);
  if (!planId) return SLA_PLAN_FALLBACK;
  return SLA_PLAN_CONFIG[planId] || SLA_PLAN_FALLBACK;
}
function slaAgent(id) { return SLA_AGENTS.find(a => a.id === id) || null; }
function slaCoverageFor(priority) { return SLA_COVERAGE[priority] || SLA_COVERAGE.normal; }
function slaIs24x7(priority) { return slaCoverageFor(priority).mode === "24x7"; }

function slaFmtMin(min) {
  const sign = min < 0 ? "-" : "";
  const abs = Math.abs(Math.round(min));
  if (abs < 60) return `${sign}${abs}m`;
  const h = Math.floor(abs / 60), m = abs % 60;
  if (h < 24) return m === 0 ? `${sign}${h}h` : `${sign}${h}h ${m}m`;
  const d = Math.floor(h / 24), rh = h % 24;
  return rh === 0 ? `${sign}${d}d` : `${sign}${d}d ${rh}h`;
}

// Returns active (non-paused) elapsed minutes between createdAtMin and simNowMin.
function slaActiveElapsed(createdAtMin, priority, simNowMin = 0) {
  const totalElapsed = simNowMin - createdAtMin;
  if (totalElapsed <= 0) return 0;
  if (slaIs24x7(priority)) return totalElapsed;

  // For business-hours coverage, walk in 10-min chunks anchored to wall clock.
  const realNow = Date.now();
  const startMs = realNow + (createdAtMin * 60000);
  const endMs   = realNow + (simNowMin * 60000);
  if (endMs <= startMs) return 0;

  let active = 0;
  const STEP = 10 * 60000;
  for (let t = startMs; t < endMs; t += STEP) {
    const d = new Date(t);
    const day = d.getDay();
    const hour = d.getHours();
    const iso = d.toISOString().slice(0, 10);
    if (SLA_HOLIDAYS.some(h => h.date === iso)) continue;
    if (!SLA_BUSINESS_HOURS.weekdays.includes(day)) continue;
    if (hour < SLA_BUSINESS_HOURS.start || hour >= SLA_BUSINESS_HOURS.end) continue;
    active += Math.min(STEP, endMs - t) / 60000;
  }
  return active;
}

function slaIsBusinessNow(simNowMin = 0) {
  const d = new Date(Date.now() + simNowMin * 60000);
  const iso = d.toISOString().slice(0, 10);
  if (SLA_HOLIDAYS.some(h => h.date === iso)) return false;
  if (!SLA_BUSINESS_HOURS.weekdays.includes(d.getDay())) return false;
  if (d.getHours() < SLA_BUSINESS_HOURS.start || d.getHours() >= SLA_BUSINESS_HOURS.end) return false;
  return true;
}

function slaAgentEffectiveStatus(agent, simNowMin = 0) {
  if (!agent) return "off_duty";
  if (agent.status === "on_leave") return "on_leave";
  if (agent.status === "off_duty") return "off_duty";
  if (agent.hours) {
    const realNow = new Date(Date.now() + simNowMin * 60000);
    const h = realNow.getHours();
    if (h < agent.hours.start || h >= agent.hours.end) return "off_duty";
  }
  return agent.status;
}

// Compute SLA state for a ticket. Pass either a raw ticket (we'll adapt)
// or a pre-shaped one. Returns { state, dueAtMin, replyInMin, remainingMin, isPaused, cfg, ... }.
function slaCompute(rawTicket, customer, simNowMin = 0) {
  const ticket = rawTicket && rawTicket.createdAtMin != null
    ? rawTicket
    : _ticketToSlaShape(rawTicket);
  if (!ticket) return { state: "ok", dueAtMin: 0, isPaused: false, cfg: SLA_PLAN_FALLBACK };

  const cfg = slaPlanFor(customer);
  const dueAt = cfg.firstReplyMin;
  const isPaused = !slaIs24x7(ticket.priority) && !slaIsBusinessNow(simNowMin);

  if (ticket.firstReplyAtMin != null) {
    const replyElapsed = slaActiveElapsed(ticket.createdAtMin, ticket.priority, ticket.firstReplyAtMin);
    return {
      state: replyElapsed <= dueAt ? "met" : "missed",
      met: replyElapsed <= dueAt,
      replyInMin: replyElapsed,
      dueAtMin: dueAt,
      isPaused: false, cfg,
    };
  }

  const elapsed = slaActiveElapsed(ticket.createdAtMin, ticket.priority, simNowMin);
  const remaining = dueAt - elapsed;

  let state = "ok";
  if (remaining <= 0) state = "breached";
  else if (remaining <= 5) state = "at_risk";
  else if (remaining <= dueAt * 0.5) state = "warn";

  const breachedByMin = remaining < 0 ? -remaining : 0;
  return {
    state, dueAtMin: dueAt, elapsedActiveMin: elapsed, remainingMin: remaining,
    breachedByMin, isPaused, cfg,
  };
}

// Notification cascade simulator. Returns events that would have fired by
// `simNowMin`, ordered by time. Promotes through the responder chain when
// the current responder is unavailable.
function slaSimulate(rawTicket, customer, simNowMin = 0) {
  const ticket = rawTicket && rawTicket.createdAtMin != null
    ? rawTicket
    : _ticketToSlaShape(rawTicket);
  if (!ticket) return [];

  const cfg = slaPlanFor(customer);
  const responders = [
    slaAgent(ticket.firstResponderId),
    slaAgent(ticket.secondResponderId),
    slaAgent(ticket.thirdResponderId),
  ];

  const events = [];

  function effectiveResponderAt(level, atMin) {
    for (let i = level; i < responders.length; i++) {
      const a = responders[i];
      if (!a) continue;
      const status = slaAgentEffectiveStatus(a, atMin);
      if (status === "available" || status === "busy") {
        return { agent: a, promotedFrom: i > level ? level : null, level: i };
      }
    }
    return { agent: responders[level] || null, level };
  }

  function emit(atMin, kind, reason, agent, channels = ["email", "whatsapp"], promotedFrom = null) {
    if (!agent) return;
    if (atMin > simNowMin) return;
    channels.forEach(ch => {
      if (!agent.channels[ch]) return;
      events.push({
        atMin, kind, reason,
        agentId: agent.id, agentName: agent.name, agentInitials: agent.initials, agentColor: agent.color,
        channel: ch, promotedFrom,
      });
    });
  }

  {
    const r = effectiveResponderAt(0, ticket.createdAtMin);
    emit(ticket.createdAtMin, "created", "Ticket created — notifying first responder",
         r.agent, ["email", "whatsapp"], r.promotedFrom);
  }

  const halfway = ticket.createdAtMin + Math.round(cfg.firstReplyMin * 0.5);
  {
    const r = effectiveResponderAt(0, halfway);
    if (ticket.firstReplyAtMin == null || halfway < ticket.firstReplyAtMin) {
      emit(halfway, "halfway", `Halfway through SLA window (${cfg.firstReplyMin / 2} min elapsed)`,
           r.agent, ["email"], r.promotedFrom);
    }
  }

  if (ticket.firstReplyAtMin != null) {
    const replyElapsed = slaActiveElapsed(ticket.createdAtMin, ticket.priority, ticket.firstReplyAtMin);
    if (replyElapsed <= cfg.firstReplyMin) {
      emit(ticket.firstReplyAtMin, "replied", "First reply sent — SLA met ✓",
           responders[0], ["email"]);
      return events.sort((a, b) => a.atMin - b.atMin);
    }
  }

  const breachAt = ticket.createdAtMin + cfg.firstReplyMin;
  {
    const r = effectiveResponderAt(1, breachAt);
    emit(breachAt, "breach", "SLA breached — escalating to L2",
         r.agent, ["email", "whatsapp"], r.promotedFrom);
    if (responders[0]) emit(breachAt, "breach_cc", "CC'd — your SLA window expired", responders[0], ["email"]);
  }

  let t = breachAt + cfg.reminderMin;
  let escalateLevel = 1;
  while (t <= simNowMin) {
    const breachedBy = t - breachAt;
    const cadence = breachedBy >= cfg.severeAtMin ? cfg.severeReminderMin : cfg.reminderMin;
    if (breachedBy >= cfg.severeAtMin && escalateLevel === 1) {
      escalateLevel = 2;
      const r = effectiveResponderAt(2, t);
      emit(t, "severe", `Severe — ${breachedBy}m past breach. Escalating to L3.`,
           r.agent, ["email", "whatsapp"], r.promotedFrom);
    } else {
      const r = effectiveResponderAt(escalateLevel, t);
      emit(t, "reminder", `Reminder · ${breachedBy}m past breach`,
           r.agent, ["whatsapp"], r.promotedFrom);
    }
    t += cadence;
  }

  return events.sort((a, b) => a.atMin - b.atMin);
}

// ── Components ──────────────────────────────────────────

function SlaPill({ ticket, customer, simNowMin = 0, compact = false }) {
  const s = slaCompute(ticket, customer, simNowMin);
  const cls = `sla-pill sla-${s.state}` + (compact ? " sla-compact" : "");
  let label;
  if (s.state === "met") label = `Met · ${slaFmtMin(s.replyInMin)}`;
  else if (s.state === "missed") label = `Missed by ${slaFmtMin(s.replyInMin - s.dueAtMin)}`;
  else if (s.state === "breached") label = `Breached · ${slaFmtMin(-s.remainingMin)} over`;
  else if (s.state === "at_risk") label = `At risk · ${slaFmtMin(s.remainingMin)} left`;
  else if (s.state === "warn") label = `${slaFmtMin(s.remainingMin)} left`;
  else label = `${slaFmtMin(s.remainingMin)} left`;
  return (
    <span className={cls} title={s.cfg ? `Plan SLA: ${s.cfg.firstReplyMin}m first reply` : ""}>
      <span className="sla-dot"/>
      {label}
      {s.isPaused && <span className="sla-paused">paused</span>}
    </span>
  );
}

function SlaAgentBadge({ agent, simNowMin = 0, size = "md", showRole = false }) {
  if (!agent) {
    return (
      <span className={`sla-agent sla-agent-${size} is-empty`}>
        <span className="sla-agent-avatar" style={{ background: "#e6e8ee", color: "#9aa0ae" }}>—</span>
        <span className="sla-agent-text">Unassigned</span>
      </span>
    );
  }
  const status = slaAgentEffectiveStatus(agent, simNowMin);
  return (
    <span className={`sla-agent sla-agent-${size} status-${status}`}>
      <span className="sla-agent-avatar" style={{ background: agent.color }}>
        {agent.initials}
        <span className={`sla-presence presence-${status}`}/>
      </span>
      <span className="sla-agent-text">
        <span className="sla-agent-name">{agent.name}</span>
        {showRole && <span className="sla-agent-role">{agent.role}</span>}
      </span>
    </span>
  );
}

function SlaResponderChain({ ticket, simNowMin = 0 }) {
  const shaped = ticket && ticket.createdAtMin != null ? ticket : _ticketToSlaShape(ticket);
  const chain = [
    { label: "L1", agent: slaAgent(shaped && shaped.firstResponderId) },
    { label: "L2", agent: slaAgent(shaped && shaped.secondResponderId) },
    { label: "L3", agent: slaAgent(shaped && shaped.thirdResponderId) },
  ];
  return (
    <div className="sla-chain">
      {chain.map((x, i) => (
        <React.Fragment key={i}>
          <div className="sla-chain-step">
            <div className="sla-chain-level">{x.label}</div>
            <SlaAgentBadge agent={x.agent} simNowMin={simNowMin} size="sm" showRole/>
          </div>
          {i < chain.length - 1 && <div className="sla-chain-arrow">→</div>}
        </React.Fragment>
      ))}
    </div>
  );
}

function SlaStrip({ ticket, customer, simNowMin = 0, onAdvance, onReset }) {
  const s = slaCompute(ticket, customer, simNowMin);
  const cov = slaCoverageFor(ticket && ticket.priority);
  const planLabel = customer && (customer.planId || customer.plan_id)
    ? (customer.planId || customer.plan_id).toString().replace(/^./, c => c.toUpperCase())
    : "No plan";

  let stateLabel, stateDesc;
  if (s.state === "met") {
    stateLabel = "✓ SLA met";
    stateDesc = `Replied in ${slaFmtMin(s.replyInMin)} (limit ${slaFmtMin(s.dueAtMin)})`;
  } else if (s.state === "missed") {
    stateLabel = "✗ SLA missed";
    stateDesc = `Replied in ${slaFmtMin(s.replyInMin)}, ${slaFmtMin(s.replyInMin - s.dueAtMin)} late`;
  } else if (s.state === "breached") {
    stateLabel = "⚠ Breached";
    stateDesc = `${slaFmtMin(-s.remainingMin)} past first-reply limit · escalations active`;
  } else if (s.state === "at_risk") {
    stateLabel = "⏱ At risk";
    stateDesc = `${slaFmtMin(s.remainingMin)} until breach`;
  } else {
    stateLabel = "On track";
    stateDesc = `${slaFmtMin(s.remainingMin)} until breach`;
  }

  // The bar visualizes 0 → 1.5× SLA. Convert "fraction of SLA" to
  // "fraction of bar" by dividing by 1.5 — otherwise the overflow segment
  // (which sits at left:66.66% with width = breachedFrac in SLA units)
  // would extend past the right edge of the bar (e.g. breachedFrac=0.5
  // would put the overflow's right edge at 116% of the bar, breaking out
  // of the card layout).
  const elapsedFrac = s.replyInMin != null
    ? Math.min(1.5, s.replyInMin / s.dueAtMin)
    : Math.min(1.5, (s.elapsedActiveMin || 0) / s.dueAtMin);
  // Fill grows from 0 to the limit marker (66.66%) as elapsed reaches the
  // SLA. Past the limit the fill stays put and the overflow takes over.
  const fillPct     = Math.min(100, (Math.min(1, elapsedFrac) / 1.5) * 100);
  // Overflow extends from the marker at 66.66% up to the right edge
  // (33.33% wide max).
  const overflowPct = Math.max(0, (elapsedFrac - 1) / 1.5) * 100;

  return (
    <div className={`sla-strip sla-state-${s.state}`}>
      <div className="sla-strip-head">
        <div className="sla-strip-title">
          <span className="sla-strip-state">{stateLabel}</span>
          <span className="sla-strip-desc">{stateDesc}</span>
        </div>
        <div className="sla-strip-meta">
          <span className="sla-strip-meta-item"><b>{planLabel}</b> plan · first reply {s.dueAtMin}m</span>
          <span className="sla-strip-sep">·</span>
          <span className="sla-strip-meta-item">{cov.label}</span>
          {s.isPaused && <span className="sla-paused-chip">⏸ Paused — outside business hours</span>}
        </div>
      </div>

      <div className="sla-strip-bar">
        <div className="sla-bar-track">
          <div className="sla-bar-fill" style={{ width: `${fillPct}%` }}/>
          {overflowPct > 0 && (
            <div className="sla-bar-overflow" style={{ width: `${overflowPct}%` }}/>
          )}
          <div className="sla-bar-marker" style={{ left: `${100 / 1.5}%` }}>
            <span className="sla-bar-marker-label">Limit · {s.dueAtMin}m</span>
          </div>
        </div>
        <div className="sla-bar-legend">
          <span>0m</span><span>{Math.round(s.dueAtMin * 1.5)}m</span>
        </div>
      </div>

      {(onAdvance || onReset) && (
        <div className="sla-strip-sim">
          <span className="sla-sim-label">Simulator:</span>
          <span className="sla-sim-now">+{simNowMin}m</span>
          {onAdvance && <button className="btn sla-sim-btn" onClick={() => onAdvance(5)}>+5m</button>}
          {onAdvance && <button className="btn sla-sim-btn" onClick={() => onAdvance(15)}>+15m</button>}
          {onAdvance && <button className="btn sla-sim-btn" onClick={() => onAdvance(60)}>+1h</button>}
          {onReset && <button className="btn sla-sim-btn" onClick={onReset}>Reset</button>}
        </div>
      )}
    </div>
  );
}

function SlaNotificationLog({ ticket, customer, simNowMin = 0 }) {
  const events = slaSimulate(ticket, customer, simNowMin);
  if (!events.length) {
    return <div className="sla-log-empty">No notifications yet for this ticket.</div>;
  }
  return (
    <div className="sla-log">
      {events.map((ev, i) => (
        <div key={i} className={`sla-log-item kind-${ev.kind}`}>
          <div className="sla-log-time">{slaFmtMin(ev.atMin)}</div>
          <div className="sla-log-dot" style={{ background: ev.agentColor }}/>
          <div className="sla-log-body">
            <div className="sla-log-line1">
              <span className="sla-log-channel">
                {ev.channel === "email" ? "✉ Email" : "💬 WhatsApp"}
              </span>
              <span className="sla-log-arrow">→</span>
              <span className="sla-log-agent" style={{ color: ev.agentColor }}>
                <b>{ev.agentName}</b>
              </span>
              {ev.promotedFrom != null && (
                <span className="sla-log-promoted">↳ promoted (L{ev.promotedFrom + 1} unavailable)</span>
              )}
            </div>
            <div className="sla-log-reason">{ev.reason}</div>
          </div>
        </div>
      ))}
    </div>
  );
}

// ── Settings: Team & SLA tab ─────────────────────────────
function SlaTeamSettings() {
  return (
    <div className="sla-settings">
      <div className="sup-group" style={{ "--sup-group-color": "#0073ea" }}>
        <div className="sup-group-head">
          <SupChev open={true}/>
          <span className="sup-group-title">Support team</span>
          <span className="sup-group-count">{SLA_AGENTS.length}</span>
          <button className="btn" style={{ marginLeft: "auto" }}>+ Invite teammate</button>
        </div>
        <div className="sup-group-table-wrap">
          <table className="sup-t">
            <thead><tr>
              <th className="sup-th-name">Agent</th>
              <th>Role</th>
              <th>Working hours</th>
              <th>Channels</th>
              <th>On-call for</th>
              <th className="sup-th-center">Status</th>
              <th className="sup-th-actions">Actions</th>
            </tr></thead>
            <tbody>
              {SLA_AGENTS.map(a => (
                <tr key={a.id} className="sup-tr">
                  <td className="sup-td-name">
                    <SlaAgentBadge agent={a} size="md"/>
                    <div className="sup-td-customer-sub" style={{ marginLeft: 38 }}>{a.email}</div>
                  </td>
                  <td>{a.role}</td>
                  <td>{a.hours ? a.hours.label : <span style={{ color: "var(--ink-faint)" }}>Workspace default</span>}</td>
                  <td>
                    <div className="sla-channel-row">
                      <span className={`sla-ch ${a.channels.email ? "on" : ""}`}>✉ Email</span>
                      <span className={`sla-ch ${a.channels.whatsapp ? "on" : ""}`}>💬 WhatsApp</span>
                    </div>
                  </td>
                  <td>
                    {a.onCall.length === 0
                      ? <span style={{ color: "var(--ink-faint)" }}>—</span>
                      : a.onCall.map(p => <span key={p} className={`sup-prio sup-prio-${p}`} style={{ marginRight: 4 }}>{p}</span>)}
                  </td>
                  <td className="sup-td-center">
                    <span className={`sla-status-pill status-${a.status}`}>
                      {a.status === "available" ? "Available"
                        : a.status === "busy" ? "Busy"
                        : a.status === "off_duty" ? "Off duty"
                        : "On leave"}
                    </span>
                  </td>
                  <td style={{ textAlign: "right" }}>
                    <button className="btn">Edit</button>
                    <button className="btn" style={{ marginLeft: 6 }}>Schedule</button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      <div className="sup-group" style={{ "--sup-group-color": "#a25ddc" }}>
        <div className="sup-group-head">
          <SupChev open={true}/>
          <span className="sup-group-title">First-response SLA per plan</span>
          <span className="sup-group-count">3</span>
        </div>
        <div className="sup-group-table-wrap">
          <table className="sup-t">
            <thead><tr>
              <th className="sup-th-name">Plan</th>
              <th className="sup-th-center">First-reply window</th>
              <th className="sup-th-center">Reminder cadence (after breach)</th>
              <th className="sup-th-center">Severe threshold</th>
              <th className="sup-th-center">Severe cadence</th>
            </tr></thead>
            <tbody>
              {Object.entries(SLA_PLAN_CONFIG).map(([planId, cfg]) => (
                <tr key={planId} className="sup-tr">
                  <td className="sup-td-name" style={{ textTransform: "capitalize" }}>{planId}</td>
                  <td className="sup-td-center"><b>{cfg.firstReplyMin}m</b></td>
                  <td className="sup-td-center">every <b>{cfg.reminderMin}m</b></td>
                  <td className="sup-td-center">{cfg.severeAtMin}m past breach</td>
                  <td className="sup-td-center">every <b>{cfg.severeReminderMin}m</b></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      <div className="sup-group" style={{ "--sup-group-color": "#fdab3d" }}>
        <div className="sup-group-head">
          <SupChev open={true}/>
          <span className="sup-group-title">Coverage by priority</span>
          <span className="sup-group-count">4</span>
        </div>
        <div className="sup-group-table-wrap">
          <table className="sup-t">
            <thead><tr>
              <th className="sup-th-name">Priority</th>
              <th className="sup-th-center">Coverage mode</th>
              <th>Description</th>
            </tr></thead>
            <tbody>
              {Object.entries(SLA_COVERAGE).map(([prio, c]) => (
                <tr key={prio} className="sup-tr">
                  <td className="sup-td-name"><span className={`sup-prio sup-prio-${prio}`}>{prio}</span></td>
                  <td className="sup-td-center">
                    <span className={`sla-coverage-pill mode-${c.mode}`}>
                      {c.mode === "24x7" ? "24 / 7" : "Business hours"}
                    </span>
                  </td>
                  <td>{c.label}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      <div className="sla-two-col">
        <div className="sup-group" style={{ "--sup-group-color": "#00c875" }}>
          <div className="sup-group-head">
            <SupChev open={true}/>
            <span className="sup-group-title">Business hours</span>
            <button className="btn" style={{ marginLeft: "auto" }}>Edit</button>
          </div>
          <div className="sla-bh-card">
            <div className="sla-bh-row"><span className="sla-bh-label">Timezone</span><span><b>{SLA_BUSINESS_HOURS.timezone}</b></span></div>
            <div className="sla-bh-row"><span className="sla-bh-label">Hours</span><span><b>{SLA_BUSINESS_HOURS.start}:00 – {SLA_BUSINESS_HOURS.end}:00</b></span></div>
            <div className="sla-bh-row"><span className="sla-bh-label">Working days</span>
              <div className="sla-weekdays">
                {["Sun","Mon","Tue","Wed","Thu","Fri","Sat"].map((d, i) => (
                  <span key={i} className={`sla-wd ${SLA_BUSINESS_HOURS.weekdays.includes(i) ? "on" : ""}`}>{d}</span>
                ))}
              </div>
            </div>
            <div className="sla-bh-note">
              SLAs for <b>urgent</b> tickets ignore these hours and run 24 / 7.
              Other priorities pause outside hours and on holidays.
            </div>
          </div>
        </div>

        <div className="sup-group" style={{ "--sup-group-color": "#e2445c" }}>
          <div className="sup-group-head">
            <SupChev open={true}/>
            <span className="sup-group-title">Holidays — 2026</span>
            <span className="sup-group-count">{SLA_HOLIDAYS.length}</span>
            <button className="btn" style={{ marginLeft: "auto" }}>+ Add</button>
          </div>
          <div className="sla-holiday-list">
            {SLA_HOLIDAYS.map(h => (
              <div key={h.date} className="sla-holiday">
                <span className="sla-holiday-date">{new Date(h.date).toLocaleDateString("en-US", { month: "short", day: "numeric" })}</span>
                <span className="sla-holiday-label">{h.label}</span>
                <button className="sla-holiday-x" title="Remove">×</button>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

// Tiny shared chev — also used by support.jsx group cards.
function SupChev({ open }) {
  return (
    <svg className="sup-group-chev" viewBox="0 0 16 16" fill="none"
         style={{ transform: open ? "none" : "rotate(-90deg)" }}>
      <path d="M5 6l3 3 3-3" stroke="currentColor" strokeWidth="1.6"
            strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

Object.assign(window, {
  SLA_AGENTS, SLA_PLAN_CONFIG, SLA_COVERAGE, SLA_BUSINESS_HOURS, SLA_HOLIDAYS,
  slaPlanFor, slaAgent, slaCoverageFor, slaCompute, slaSimulate,
  slaActiveElapsed, slaIsBusinessNow, slaAgentEffectiveStatus, slaFmtMin,
  SlaPill, SlaAgentBadge, SlaResponderChain, SlaStrip, SlaNotificationLog, SlaTeamSettings,
  SupChev,
});
