/* page-refunds.jsx — Refunds module (03-ui §2, Review 9).
   All roles share one role-parameterised component (GA / CM / AM / OM).
   List + 700px DetailDrawer + in-page manual-capture mode.
   IIFE-wrapped per the multi-file Babel architecture (prototype-standards §29). */
(function () {
  const { useState, useMemo } = React;

  // ── Currency formatter (pre-formatted string from numeric amount) ──────────
  const CURRENCY_SYMBOL = { SGD: "S$", PHP: "₱", IDR: "Rp ", THB: "฿", MYR: "RM " };
  const _fmtRefundAmount = (amount, country_id) => {
    const country = SB2_COUNTRY_BY_ID[country_id];
    const sym = (country && CURRENCY_SYMBOL[country.currency_code]) || "";
    if (amount == null) return "—";
    return `${sym}${Number(amount).toLocaleString()}`;
  };

  // ── GeoScope helper (shared pattern from page-orders) ────────────────────
  const _geoData = () => ({
    countries: SB2_COUNTRIES.map(c => ({ value: c.country_id, label: c.country_name })),
    areas:     SB3_AREAS.map(a => ({ value: a.id, label: a.name, country_id: a.country_id })),
    outlets:   SB3_OUTLETS.map(o => ({ value: o.id, label: o.name, area_id: o.area_id })),
  });

  // ── Refund reason tag helpers ────────────────────────────────────────────
  const REFUND_REASON_TAGS = (typeof CUSTOM_OPTIONS !== "undefined" ? CUSTOM_OPTIONS : [])
    .filter(o => o.option_type === "refund_reason_tag");
  const _reasonLabel = (id) => {
    const tag = REFUND_REASON_TAGS.find(t => t.id === id);
    return tag ? tag.label : (id || "—");
  };
  const _reasonRequiresRemark = (id) => {
    const tag = REFUND_REASON_TAGS.find(t => t.id === id);
    return tag ? tag.requires_remark : false;
  };

  // ── Scope baseline helpers ────────────────────────────────────────────────
  // CM = country PH, AM = area ar_03, OM = outlet SH-PH-001 (mirrors page-orders)
  const CM_COUNTRY   = "PH";
  const AM_AREA      = (typeof AM_AREA_ID !== "undefined" ? AM_AREA_ID : "ar_03");
  const OM_OUTLET    = (typeof OM_OUTLET_ID !== "undefined" ? OM_OUTLET_ID : "SH-PH-001");

  const _scopeOutletIds = (role) => {
    if (role === "CM") return new Set(SB3_OUTLETS.filter(o => o.country_id === CM_COUNTRY).map(o => o.id));
    if (role === "AM") return new Set(SB3_OUTLETS.filter(o => o.area_id === AM_AREA).map(o => o.id));
    if (role === "OM") return new Set([OM_OUTLET]);
    return null; // GA: all
  };

  // Map outlet_id → country_id (for scope filtering on refunds which have country_id directly)
  const _scopeCountries = (role) => {
    if (role === "CM") return new Set([CM_COUNTRY]);
    if (role === "AM") {
      const area = SB3_AREA_BY_ID[AM_AREA];
      return area ? new Set([area.country_id]) : new Set(["PH"]);
    }
    if (role === "OM") {
      const outlet = SB3_OUTLET_BY_ID[OM_OUTLET];
      return outlet ? new Set([outlet.country_id]) : new Set(["PH"]);
    }
    return null; // GA: all
  };

  // ── RefundsList ───────────────────────────────────────────────────────────
  /** @spec US-065/US-066 — Refunds (list · detail · manual capture) */
  function RefundsList({ role = "GA", scope }) {
    if (!["GA", "CM", "AM", "OM"].includes(role)) return _notAuthorised;

    // ── Scope ────────────────────────────────────────────────────────────────
    const scopeCountries = useMemo(() => _scopeCountries(role), [role]);

    // Stateful rows — so status transitions (approve / reject / withdraw / issue) and
    // manual capture actually mutate the displayed list. Was a non-stateful SB5_REFUNDS
    // read, which left the ApprovalCard buttons cosmetic (audit+toast only, no status change).
    const [refunds, setRefunds] = useState(() => SB5_REFUNDS.map(r => ({ ...r })));

    const baseRows = useMemo(() =>
      refunds.filter(r =>
        !scopeCountries || scopeCountries.has(r.country_id)
      ),
    [refunds, scopeCountries]);

    // ── Filter state ─────────────────────────────────────────────────────────
    const [primaryValue, setPrimaryValue] = useState({ status: "", method: "" });
    const [advancedValues, setAdvancedValues] = useState({ reason_tag_id: "", geo: null, dtf: null });
    const [search, setSearch] = useState("");
    const [page, setPage] = useState(1);
    const [pageSize, setPageSize] = useState(20);

    // ── Drawer state ─────────────────────────────────────────────────────────
    const [drawerRefund, setDrawerRefund] = useState(null);

    // ── Create-refund drawer (manual-capture) ─────────────────────────────────
    const [createOpen, setCreateOpen] = useState(false);

    // ── Confirm modal state ───────────────────────────────────────────────────
    const [confirmModal, setConfirmModal] = useState(null); // { action, refund }

    // ── Toast (submit confirmation) ─────────────────────────────────────────────
    const [toast, setToast] = useState("");
    const fireToast = (msg) => { setToast(msg); setTimeout(() => setToast(""), 2600); };

    // ── Derived / filtered rows ───────────────────────────────────────────────
    const filteredRows = useMemo(() => {
      const q = search.trim().toLowerCase();
      return baseRows
        .filter(r => !primaryValue.status || r.status === primaryValue.status)
        .filter(r => !primaryValue.method || r.method === primaryValue.method)
        .filter(r => !advancedValues.reason_tag_id || r.reason_tag_id === advancedValues.reason_tag_id)
        .filter(r => {
          const g = advancedValues.geo;
          if (!g) return true;
          if (g.countries && g.countries.length && !g.countries.includes(r.country_id)) return false;
          if (g.areas && g.areas.length) {
            // find outlet's area by matching country refunds to outlets
            const outletInArea = SB3_OUTLETS.find(o =>
              o.country_id === r.country_id && g.areas.includes(o.area_id)
            );
            if (!outletInArea) return false;
          }
          if (g.outlets && g.outlets.length) {
            // match order_id to outlet via SB4_ORDER_BY_ID or best-effort
            const order = r.order_id && (typeof SB4_ORDER_BY_ID !== "undefined") ? SB4_ORDER_BY_ID[r.order_id] : null;
            if (!order || !g.outlets.includes(order.store_id)) return false;
          }
          return true;
        })
        .filter(r => !advancedValues.dtf || _dtfMatch(advancedValues.dtf, r.ts, r.country_id))
        .filter(r => {
          if (!q) return true;
          return (
            (r.order_number && r.order_number.toLowerCase().includes(q)) ||
            (r.customer_name && r.customer_name.toLowerCase().includes(q)) ||
            (r.issued_by && r.issued_by.toLowerCase().includes(q))
          );
        });
    }, [baseRows, primaryValue, advancedValues, search]);

    const totalPages = Math.max(1, Math.ceil(filteredRows.length / pageSize));
    const visibleRows = filteredRows.slice((page - 1) * pageSize, page * pageSize);

    // ── FilterBar config ─────────────────────────────────────────────────────
    const statusOptions = [
      { value: "", label: "All statuses" },
      { value: "pending_approval", label: "Pending approval" },
      { value: "approved",         label: "Approved" },
      { value: "succeeded",        label: "Succeeded" },
      { value: "failed",           label: "Failed" },
      { value: "rejected",         label: "Rejected" },
    ];
    const methodOptions = [
      { value: "", label: "All methods" },
      { value: "gateway", label: "Gateway" },
      { value: "manual",  label: "Manual" },
    ];
    const primaryFilterArr = [
      { key: "status", label: "Status", options: statusOptions },
      { key: "method", label: "Method", options: methodOptions },
    ];

    const geoData = _geoData();
    const advancedFilters = [
      // reason_tag_id — GA/CM only
      ...(["GA", "CM"].includes(role) ? [{
        key: "reason_tag_id",
        kind: "select",
        label: "Reason tag",
        options: [
          { value: "", label: "All reasons" },
          ...REFUND_REASON_TAGS.map(t => ({ value: t.id, label: t.label })),
        ],
      }] : []),
      // GeoScope — GA/CM/AM only (omit for OM)
      ...(role !== "OM" ? [{
        key: "geo",
        kind: "geoscope",
        label: "Network scope",
        role,
        countries: geoData.countries,
        areas:     geoData.areas,
        outlets:   geoData.outlets,
      }] : []),
      // date+time on ts (created_at) — §36 DateTimeFilter (range mode lives inside the datetime kind)
      { key: "dtf", kind: "datetime", label: "Date (created)", country: role !== "OM" ? (scope && scope.countryId) || "SG" : "PH" },
    ];

    const handleReset = () => {
      setPrimaryValue({ status: "", method: "" });
      setAdvancedValues({ reason_tag_id: "", geo: null, dtf: null });
      setSearch("");
      setPage(1);
    };

    // ── Page descriptions per role (TABLE 1) ─────────────────────────────────
    const descriptions = {
      GA: "Refund requests across markets.",
      CM: "Your country's refunds.",
      AM: "Your area's refunds.",
      OM: "Your outlet's refunds.",
    };

    // ── Columns (role-branched per TABLE 1) ──────────────────────────────────
    const showExtended = role !== "OM"; // GA/CM/AM show reason_tag_id / requested_by / approved_by
    const columns = [
      {
        label: "Order", sortable: true, sortKey: "order_number",
        render: r => <span style={{ ...T.primary() }}>{r.order_number || "—"}</span>,
      },
      {
        label: "Customer", sortable: true, sortKey: "customer_name",
        render: r => <span style={{ ...T_MUTED }}>{r.customer_name || "—"}</span>,
      },
      {
        label: "Amount", sortable: true, sortKey: "amount",
        render: r => <span style={{ ...T_MUTED }}>{_fmtRefundAmount(r.amount, r.country_id)}</span>,
      },
      {
        label: "Method", sortable: true, sortKey: "method",
        render: r => <span style={{ ...T_MUTED }}>{r.method === "manual" ? "Manual" : "Gateway"}</span>,
      },
      ...(showExtended ? [
        {
          label: "Reason", sortable: true, sortKey: "reason_tag_id",
          render: r => <span style={{ ...T_MUTED }}>{_reasonLabel(r.reason_tag_id)}</span>,
        },
      ] : []),
      {
        label: "Status", sortable: false,
        render: r => <StatusPill status={r.status} kind="refund"/>,
      },
      ...(showExtended ? [
        {
          label: "Requested by", sortable: true, sortKey: "requested_by",
          render: r => <span style={{ ...T_MUTED }}>{r.requested_by || "—"}</span>,
        },
        {
          label: "Approved by", sortable: true, sortKey: "approved_by",
          render: r => <span style={{ ...T_MUTED }}>{r.approved_by || "—"}</span>,
        },
      ] : []),
      {
        label: "Created", width: 160, sortable: true, sortKey: "ts",
        render: r => <span style={{ ...T_MUTED }}>{_fmtDateTime(r.ts, r.country_id)}</span>,
      },
    ];

    return (
      <div className="page-inner">
        <PageHead
          title="Refunds"
          description={descriptions[role] || descriptions.GA}
          actions={
            <>
              <ExportButton role={role} onClick={() => fireToast("Exporting refunds…")}/>
              <Btn variant="primary" onClick={() => setCreateOpen(true)}>
                New refund
              </Btn>
            </>
          }
        />

        <FilterBar
          primaryFilter={primaryFilterArr}
          primaryValue={primaryValue}
          onPrimaryChange={v => { setPrimaryValue(v); setPage(1); }}
          advancedFilters={advancedFilters}
          advancedValues={advancedValues}
          onAdvancedChange={(k, v) => { setAdvancedValues(prev => ({ ...prev, [k]: v })); setPage(1); }}
          onAdvancedReset={() => { setAdvancedValues({ reason_tag_id: "", geo: null, dtf: null }); setPage(1); }}
          onReset={handleReset}
          search={search}
          onSearch={v => { setSearch(v); setPage(1); }}
          searchPlaceholder="Search refunds…"
        />

        <Table
          columns={columns}
          rows={visibleRows}
          onRow={r => setDrawerRefund(r)}
          emptyText="No refunds match this filter."
        />
        <TableFooter
          page={page}
          totalPages={totalPages}
          onPage={setPage}
          count={pageSize}
          onCountChange={c => { setPageSize(c); setPage(1); }}
        />

        {createOpen && (
          <RefundCaptureForm
            role={role}
            open={createOpen}
            onCancel={() => setCreateOpen(false)}
            onSubmit={(p) => {
              _pushAudit({ action: "refund_request", entity_type: "refund", diff: { method: p.method, status: p.status } });
              setRefunds(rs => [{
                id: "rf_" + (9000 + rs.length),
                ts: new Date().toISOString(),
                country_id: p.country_id,
                franchise_id: (SB2_COUNTRY_BY_ID[p.country_id] || {}).franchise_id || null,
                order_id: p.order_id || null,
                order_number: p.order_number || "—",
                customer_name: p.customer_name || "—",
                amount: p.amount,
                method: p.method,
                status: p.status,
                reason_code: p.reason_tag_id || "customer_request",
                reason_tag_id: p.reason_tag_id || null,
                reason_remark: p.reason_remark || "",
                issued_by: "you",
                issued_by_role: role,
                requested_by: "you",
                approved_by: p.status === "succeeded" ? "you" : null,
                recon_status: "unmatched",
                provider_ref: null,
                limit_at_time: null,
              }, ...rs]);
              setCreateOpen(false);
              fireToast(p.status === "pending_approval"
                ? `Refund sent to ${(p.escalateTo || "approver").toUpperCase()} for approval.`
                : "Refund issued.");
            }}
          />
        )}

        {drawerRefund && (
          <RefundDetailDrawer
            refund={drawerRefund}
            role={role}
            onClose={() => setDrawerRefund(null)}
            onAction={(action, refund) => {
              setDrawerRefund(null);
              setConfirmModal({ action, refund });
            }}
            onApproval={(action, refund, reason) => {
              // ApprovalCard escalation actions — no ConfirmModal (the card owns its own
              // reject-reason modal). Fire audit + toast directly.
              _pushAudit({
                action: action === "approve" ? "refund_approve"
                  : action === "reject"   ? "refund_reject"
                  : "refund_withdraw",
                entity_type: "refund",
                entity_id: refund.id,
                diff: action === "reject" ? { action, reason } : { action },
              });
              // Mutate status so the transition is visible. Withdraw has no enum target
              // (refund states: pending_approval/approved/succeeded/failed/rejected — no
              // draft/withdrawn) → the un-actioned request is removed. Flagged for Tricia
              // in docs/specs/v2/06-status.md (open question OQ-STATUS-WITHDRAW).
              setRefunds(rs => rs.flatMap(r => {
                if (r.id !== refund.id) return [r];
                if (action === "approve") return [{ ...r, status: "approved", approved_by: "you" }];
                if (action === "reject")  return [{ ...r, status: "rejected", reason_remark: reason || r.reason_remark }];
                return []; // withdraw — remove the retracted request
              }));
              setDrawerRefund(null);
              fireToast(
                action === "approve" ? "Refund approved."
                  : action === "reject" ? "Refund rejected."
                  : "Refund request withdrawn."
              );
            }}
          />
        )}

        {confirmModal && (
          <RefundConfirmModal
            action={confirmModal.action}
            refund={confirmModal.refund}
            role={role}
            onConfirm={() => {
              const { action, refund } = confirmModal;
              _pushAudit({
                action: action === "approve" ? "refund_approve"
                  : action === "reject"  ? "refund_reject"
                  : "refund_complete",
                entity_type: "refund",
                entity_id: refund.id,
                diff: { action },
              });
              // "Issue refund" (action "approve" on an already-approved refund) settles it.
              if (action === "approve") {
                setRefunds(rs => rs.map(r => r.id === refund.id ? { ...r, status: "succeeded" } : r));
              }
              setConfirmModal(null);
            }}
            onCancel={() => setConfirmModal(null)}
          />
        )}

        <Toast message={toast} show={!!toast}/>
      </div>
    );
  }

  // ── RefundDetailDrawer ────────────────────────────────────────────────────
  function RefundDetailDrawer({ refund, role, onClose, onAction, onApproval }) {
    const [remarks, addRemark, editRemark, deleteRemark] = _useRemarks("refund", refund.id, refund.refund_remarks || []);
    const CURRENT_USER = "you";
    const country = SB2_COUNTRY_BY_ID[refund.country_id] || {};
    const viewerTier = role.toLowerCase();

    // Limit + escalation check (viewer's own over-limit warning on this refund)
    const limit = _refundLimitFor(refund.country_id, viewerTier);
    const overLimit = refund.amount > limit;
    const launchShape = country.launch_shape || "om_am_cm";
    const escalateTo = overLimit ? _refundEscalationApprover(launchShape, viewerTier) : null;

    // ── ESCALATION (ApprovalCard) ──────────────────────────────────────────
    // Submitter tier = the tier of whoever requested the refund (issued_by_role).
    // The escalation approver is the next tier up per launch_shape — NOT always GA.
    const submitterTier  = (refund.issued_by_role || "").toLowerCase();
    const approverTier   = submitterTier ? _refundEscalationApprover(launchShape, submitterTier) : null;
    const isPending      = refund.status === "pending_approval";
    // Only escalated refunds get the card: pending, terminal-rejected, or a row whose
    // requester ≠ approver (a real escalation, not a self-issued direct refund).
    const isEscalated    = isPending || refund.status === "rejected"
      || (refund.requested_by && refund.approved_by && refund.requested_by !== refund.approved_by);
    const canApprove     = isPending && viewerTier === approverTier;
    const canWithdraw    = isPending && viewerTier === submitterTier;
    const approvalMessage = isPending
      ? `Awaiting ${approverTier ? approverTier.toUpperCase() : "higher-tier"} approval.`
      : refund.status === "rejected"
        ? `Rejected: ${refund.reason_remark || "no reason given"}`
        : "Approved";

    // Header actions: ApprovalCard owns the pending_approval approve/reject. The header
    // keeps only the within-limit direct "Issue refund" flow for already-approved refunds.
    const canAct = ["GA", "CM", "AM"].includes(role) || (role === "OM" && !overLimit);
    const isActionable = refund.status === "approved";

    const drawerActions = (
      <span style={{ display: "inline-flex", gap: 8 }}>
        {isActionable && canAct && (
          <Btn variant="primary" onClick={() => onAction("approve", refund)}>
            Issue refund
          </Btn>
        )}
        <Btn variant="secondary" onClick={onClose}>Close</Btn>
      </span>
    );

    return (
      <DetailDrawer
        open={!!refund}
        onClose={onClose}
        title={`Refund ${refund.order_number || refund.id}`}
        subtitle={_fmtDateTime(refund.ts, refund.country_id)}
        actions={drawerActions}
      >
        {/* Escalation approval surface — appears for escalated refunds only */}
        {isEscalated && (
          <ApprovalCard
            status={refund.status}
            kind="refund"
            message={approvalMessage}
            canApprove={canApprove}
            canWithdraw={canWithdraw}
            onApprove={() => onApproval("approve", refund)}
            onReject={(reason) => onApproval("reject", refund, reason)}
            onWithdraw={() => onApproval("withdraw", refund)}
          />
        )}

        {/* Ledger coordination note */}
        <InlineAlert kind="info">
          On completion, loyalty points are reversed{country.country_id === "SG" ? " and wallet is credited" : ""}.
        </InlineAlert>

        {/* Over-limit warning */}
        {overLimit && (
          <InlineAlert kind="warn">
            This refund amount exceeds your limit. Approval from{" "}
            <strong>{escalateTo ? escalateTo.toUpperCase() : "a higher tier"}</strong> is required.
          </InlineAlert>
        )}

        {/* Section 1 — General */}
        <FormSection title="General">
          <KeyValueGrid columns={2} items={[
            { label: "Amount",  value: _fmtRefundAmount(refund.amount, refund.country_id) },
            { label: "Method",  value: refund.method === "manual" ? "Manual" : "Gateway" },
            { label: "Status",  value: <StatusPill status={refund.status} kind="refund"/> },
          ]}/>
        </FormSection>

        {/* Section 2 — Order */}
        <FormSection title="Order">
          <KeyValueGrid columns={2} items={[
            {
              label: "Order",
              value: refund.order_id
                ? (
                  <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
                    {refund.order_number || refund.order_id}
                    <a
                      href="#"
                      className="contact-icon-btn"
                      title="View order"
                      onClick={e => {
                        e.preventDefault();
                        e.stopPropagation();
                        // Navigate to orders list; page-orders auto-opens drawer on incomingId
                        const orderRoute = role === "GA" ? "ga-orders"
                          : role === "CM" ? "cm-orders"
                          : role === "AM" ? "am-orders"
                          : "om-orders-live";
                        _go(orderRoute, { id: refund.order_id });
                      }}
                    >
                      <LIcon name="ExternalLink" size={13}/>
                    </a>
                  </span>
                )
                : "—",
            },
            { label: "Order number",       value: refund.order_number || "—" },
            { label: "Provider refund ref", value: refund.provider_ref || "—" },
          ]}/>
        </FormSection>

        {/* Section 3 — Customer (sourced from the referenced order) */}
        <FormSection title="Customer">
          <KeyValueGrid columns={2} items={[
            { label: "Name",  value: refund.customer_name || "—" },
            { label: "Phone", value: refund.hp ? _phoneLink(refund.hp) : "—" },
            { label: "Card (last 4)", value: refund.card_last4 ? `···· ${refund.card_last4}` : "—" },
          ]}/>
        </FormSection>

        {/* Section 4 — Reason */}
        <FormSection title="Reason">
          <KeyValueGrid columns={2} items={[
            { label: "Tag",   value: _reasonLabel(refund.reason_tag_id) },
            { label: "Notes", value: refund.reason_remark || "—" },
          ]}/>
        </FormSection>

        {/* Section 5 — Authority */}
        <FormSection title="Authority">
          <KeyValueGrid columns={2} items={[
            { label: "Requested by", value: refund.requested_by || "—" },
            { label: "Approved by",  value: refund.approved_by  || "—" },
            {
              label: "Limit at time",
              value: limit === Infinity || refund.limit_at_time == null
                ? "Uncapped (GA)"
                : _fmtRefundAmount(refund.limit_at_time, refund.country_id),
            },
            { label: "Created",      value: _fmtDateTime(refund.ts, refund.country_id) },
          ]}/>
        </FormSection>

        {/* Remarks — operator annotation thread (add/edit/delete-own), per Ops convention */}
        <RemarksSection
          entityType="refund"
          entityId={refund.id}
          remarks={remarks}
          onAdd={addRemark}
          role={role}
          currentUser={CURRENT_USER}
          onEdit={editRemark}
          onDelete={deleteRemark}/>
      </DetailDrawer>
    );
  }

  // ── RefundConfirmModal ────────────────────────────────────────────────────
  function RefundConfirmModal({ action, refund, role, onConfirm, onCancel }) {
    const country = SB2_COUNTRY_BY_ID[refund.country_id] || {};
    const viewerTier = role.toLowerCase();
    const limit = _refundLimitFor(refund.country_id, viewerTier);
    const overLimit = refund.amount > limit;
    const launchShape = country.launch_shape || "om_am_cm";
    const escalateTo = overLimit ? _refundEscalationApprover(launchShape, viewerTier) : null;

    const actionLabel = action === "approve"
      ? (refund.status === "approved" ? "Issue Refund" : "Approve Refund")
      : "Reject Refund";

    const body = action === "reject"
      ? `Reject this ${_fmtRefundAmount(refund.amount, refund.country_id)} refund for order ${refund.order_number || refund.order_id || "—"}? This cannot be undone.`
      : overLimit
        ? `This refund of ${_fmtRefundAmount(refund.amount, refund.country_id)} exceeds your tier limit. Approval from ${escalateTo ? escalateTo.toUpperCase() : "a higher tier"} is required before it can be issued.`
        : `Approve and issue a ${_fmtRefundAmount(refund.amount, refund.country_id)} refund for order ${refund.order_number || refund.order_id || "—"}?`;

    return (
      <ConfirmModal
        open
        title={actionLabel}
        body={body}
        destructive={action === "reject"}
        confirmLabel={actionLabel}
        onConfirm={onConfirm}
        onCancel={onCancel}
      />
    );
  }

  // ── RefundCaptureForm (700px create DetailDrawer — TABLE 3) ───────────────
  // Every refund references an existing order: search → auto-filled context →
  // method · amount · reason · notes (all required). OM or over-limit → sent for approval.
  // Hosted in the Ops create-drawer pattern (never a full page).
  function RefundCaptureForm({ role, open, onCancel, onSubmit }) {
    const viewerTier = role.toLowerCase();

    // Orders this role may refund against (scope-limited)
    const scopeCountries = _scopeCountries(role);
    const orderPool = useMemo(() =>
      SB4_ORDERS.filter(o => !scopeCountries || scopeCountries.has(o.country_id)),
    [scopeCountries]);

    const [orderQuery, setOrderQuery] = useState("");
    const [selectedOrder, setSelectedOrder] = useState(null);
    const [method, setMethod]   = useState("gateway");
    const [amountMode, setAmountMode] = useState("full"); // full | half | partial
    const [amountVal, setAmountVal] = useState("");
    const [reason, setReason]   = useState({ reason_tag_id: "", reason_remark: "" });
    const [errors, setErrors]   = useState({});

    const q = orderQuery.trim().toLowerCase();
    const orderMatches = q
      ? orderPool.filter(o =>
          (o.order_code && o.order_code.toLowerCase().includes(q)) ||
          (o.customer && o.customer.name && o.customer.name.toLowerCase().includes(q))
        ).slice(0, 6)
      : [];

    const country_id = selectedOrder ? selectedOrder.country_id : null;
    const limit       = country_id ? _refundLimitFor(country_id, viewerTier) : Infinity;
    const numericAmt   = parseFloat(amountVal) || 0;
    const overLimit    = numericAmt > 0 && limit !== Infinity && numericAmt > limit;
    const country      = country_id ? (SB2_COUNTRY_BY_ID[country_id] || {}) : {};
    const launchShape  = country.launch_shape || "om_am_cm";
    const needsApproval = role === "OM" || overLimit;
    const escalateTo    = needsApproval ? _refundEscalationApprover(launchShape, viewerTier) : null;

    // Amount type: Full (= order total, default) · Half (= total/2) · Partial (manual).
    // Editing the amount auto-selects the matching mode (Partial when ≠ full/half).
    const orderTotal = selectedOrder && selectedOrder.totals ? Number(selectedOrder.totals.total) : 0;
    const applyAmountMode = (m) => {
      setAmountMode(m);
      if (m === "full") setAmountVal(String(orderTotal));
      else if (m === "half") setAmountVal(String(orderTotal / 2));
      // partial: keep current value — user edits the input
    };
    const onAmountInput = (v) => {
      setAmountVal(v);
      const n = parseFloat(v);
      if (!isNaN(n) && n === orderTotal) setAmountMode("full");
      else if (!isNaN(n) && n === orderTotal / 2) setAmountMode("half");
      else setAmountMode("partial");
    };

    const selectOrder = (o) => {
      setSelectedOrder(o); setOrderQuery("");
      setAmountMode("full");
      setAmountVal(String(o.totals && o.totals.total != null ? o.totals.total : ""));
      setErrors(e => ({ ...e, order: undefined }));
    };

    const validateAll = () => {
      const e = {};
      if (!selectedOrder) e.order = "Select an order";
      if (!method) e.method = "Required";
      if (!amountVal || numericAmt <= 0) e.amount = "Enter a valid amount";
      if (!reason.reason_tag_id) e.reason_tag_id = "Select a reason tag";
      if (!reason.reason_remark.trim()) e.reason_remark = "Notes required";
      setErrors(e);
      return Object.keys(e).length === 0;
    };

    const submit = () => {
      if (!validateAll()) return;
      onSubmit({
        method,
        status: needsApproval ? "pending_approval" : "succeeded",
        escalateTo,
        amount: numericAmt,
        country_id,
        order_id: selectedOrder ? selectedOrder.id : null,
        order_number: selectedOrder ? (selectedOrder.order_code || selectedOrder.id) : null,
        customer_name: selectedOrder && selectedOrder.customer ? selectedOrder.customer.name : null,
        reason_tag_id: reason.reason_tag_id,
        reason_remark: reason.reason_remark,
      });
    };

    const drawerActions = (
      <span style={{ display: "inline-flex", gap: 8 }}>
        <Btn variant="secondary" onClick={onCancel}>Cancel</Btn>
        <Btn variant="primary" onClick={submit}>Capture refund</Btn>
      </span>
    );

    return (
      <DetailDrawer
        open={open}
        onClose={onCancel}
        title="New refund"
        subtitle="Issue a refund against an existing order."
        actions={drawerActions}
      >
        {/* Order — search an existing order; customer + amount come from it */}
        <FormSection title="Order">
          {!selectedOrder ? (
            <Field label="Find order" required error={errors.order}>
              <SearchBar value={orderQuery} onChange={setOrderQuery} placeholder="Search order number or customer…"/>
              {q && (orderMatches.length ? (
                <div className="manager-suggest">
                  {orderMatches.map(o => (
                    <MenuItem key={o.id} onClick={() => selectOrder(o)}>
                      {o.order_code} — {o.customer ? o.customer.name : "—"} · {_fmtRefundAmount(o.totals && o.totals.total, o.country_id)}
                    </MenuItem>
                  ))}
                </div>
              ) : (
                <div style={{ ...T_MUTED, fontSize: 13, marginTop: 10 }}>No matching orders in your scope.</div>
              ))}
            </Field>
          ) : (
            <>
              <KeyValueGrid columns={2} items={[
                { label: "Order number",   value: selectedOrder.order_code || selectedOrder.id },
                { label: "Customer",       value: selectedOrder.customer ? selectedOrder.customer.name : "—" },
                { label: "Original total", value: _fmtRefundAmount(selectedOrder.totals && selectedOrder.totals.total, selectedOrder.country_id) },
                { label: "Country",        value: country.country_name ? `${country.flag || ""} ${country.country_name}`.trim() : (country_id || "—") },
              ]}/>
              <div style={{ marginTop: 8 }}>
                <Btn variant="ghost" onClick={() => { setSelectedOrder(null); setAmountVal(""); }}>Change order</Btn>
              </div>
            </>
          )}
        </FormSection>

        {/* Refund — method + amount */}
        <FormSection title="Refund">
          <Field label="Method" required error={errors.method}>
            <SegToggle
              value={method}
              onChange={setMethod}
              ariaLabel="Refund method"
              options={[
                { value: "gateway", label: "Gateway" },
                { value: "manual",  label: "Manual" },
              ]}
            />
          </Field>
          <Field label="Refund amount" required error={errors.amount}>
            <SegToggle
              value={amountMode}
              onChange={applyAmountMode}
              ariaLabel="Refund amount type"
              options={[
                { value: "full",    label: "Full" },
                { value: "half",    label: "Half" },
                { value: "partial", label: "Partial" },
              ]}
            />
            <Input value={amountVal} onChange={onAmountInput} placeholder="0.00" type="number" min="0"/>
          </Field>
          {overLimit && (
            <InlineAlert kind="warn">
              This amount exceeds your refund limit. Approval from{" "}
              <strong>{escalateTo ? escalateTo.toUpperCase() : "a higher tier"}</strong> is required before it can be issued.
            </InlineAlert>
          )}
        </FormSection>

        {/* Reason */}
        <FormSection title="Reason">
          <Field label="Reason tag" required error={errors.reason_tag_id}>
            <Select
              value={reason.reason_tag_id}
              onChange={v => setReason(p => ({ ...p, reason_tag_id: v }))}
              options={[
                { value: "", label: "Select reason…" },
                ...REFUND_REASON_TAGS.map(t => ({ value: t.id, label: t.label })),
              ]}
            />
          </Field>
          <Field label="Notes" required error={errors.reason_remark}>
            <Textarea value={reason.reason_remark} onChange={v => setReason(p => ({ ...p, reason_remark: v }))} placeholder="Add a note for this refund…" rows={3}/>
          </Field>
        </FormSection>

        {/* Approval routing note (OM or over-limit) */}
        {needsApproval && selectedOrder && (
          <InlineAlert kind="info">
            This refund will be submitted as <strong>pending approval</strong>
            {escalateTo ? <> and routed to <strong>{escalateTo.toUpperCase()}</strong></> : ""}.
          </InlineAlert>
        )}
      </DetailDrawer>
    );
  }

  Object.assign(window, { RefundsList });
})();
