// NO PROD JSON API (bucket B — feed is a DataTables render payload or
//   {"html":...}, not data) — mock until backend (see PROD_API_INVENTORY.md)
// Represents: GET /payments/methods/ · AdminPaymentsController::show('methods') → methodsData() — see docs/ISYSTEM_REFERENCE.md §Batch 10.1
/* Traced Aug 2026 (architecture item 2). Saves through
   POST /payments/methods/config (methodConfigSave), which diffs the submitted
   values and records only what changed. The PSP directory this screen reads
   from is Payments/ProvidersController — settingsData() builds it, and the
   per-provider fee columns are what /payments/fees models. */
/* Payment Methods — per-brand × per-method configurations.
   Each config exposes: general, multi-currency list, fees, limits, and
   auto-approval rules (moved inside the method). */

const Methods = ({ brand }) => {
  window.useLocale && window.useLocale();
  const T = window.T || ((k, fb) => fb || k);
  const { METHODS, BRANDS } = window.MOCK;
  const [brandFilter, setBrandFilter] = useState(brand && brand.isAll ? "all" : (brand?.id || "all"));
  useEffect(()=>{ setBrandFilter(brand && brand.isAll ? "all" : (brand?.id || "all")); }, [brand?.id]);
  const [expanded, setExpanded] = useState(null);
  const [editing, setEditing] = useState(null);

  // Top-level filters for the brand × method grid
  const [methodQuery, setMethodQuery] = useState("");
  const [kindFilter, setKindFilter] = useState("all");
  const [statusFilter, setStatusFilter] = useState("all");
  const [currencyFilter, setCurrencyFilter] = useState("all");
  const [providerFilter, setProviderFilter] = useState("all");

  /* Column visibility — persisted to localStorage so each operator's
     layout sticks across sessions. Brand, Method and the row toggle
     remain mandatory (not hideable). */
  const METHOD_COLUMNS = [
    { key:"provider",      label:"Provider"     },
    { key:"status",        label:"Status"       },
    { key:"currencies",    label:"Currencies"   },
    { key:"min_max",       label:"Min / Max"    },
    { key:"dep_fee",       label:"Deposit fee"  },
    { key:"with_fee",      label:"Withdraw fee" },
    { key:"auto_approve",  label:"Auto-approve ≤" },
  ];
  const [methodColsVisible, setMethodColsVisible] = useState(() => {
    try {
      const stored = pbStore.get("pb-methods-columns", null);
      if (stored && typeof stored === "object") return stored;
    } catch (_e) {}
    return Object.fromEntries(METHOD_COLUMNS.map(c => [c.key, true]));
  });
  useEffect(() => {
    pbStore.set("pb-methods-columns", methodColsVisible);
  }, [methodColsVisible]);
  const [colsPopoverOpen, setColsPopoverOpen] = useState(false);
  const isColOn = (k) => methodColsVisible[k] !== false;
  const toggleCol = (k) => setMethodColsVisible(s => ({ ...s, [k]: !isColOn(k) }));
  const providers = (window.getAllProviders && window.getAllProviders()) || [];
  const rowProvider = (r) => window.lookupMethodProvider?.({ brand: r.brand, methodId: r.method.id, methodName: r.method.name }) || null;

  /* Role-access state — per brand × method row, which network roles are
     BLOCKED from using this method. Seeds from MOCK.METHOD_ROLE_BLOCKS
     (global per method) the first time a row is toggled. */
  const ROLES = window.MOCK.ROLES || [];
  const defaultBlocksFor = (methodId) => window.MOCK.METHOD_ROLE_BLOCKS?.[methodId] || [];
  const [roleBlocks, setRoleBlocks] = useState({});
  const getBlocks = (row) => roleBlocks[row.id] ?? defaultBlocksFor(row.method.id);
  const setRowBlocks = (row, next) => setRoleBlocks(prev => ({ ...prev, [row.id]: next }));
  const toggleRoleBlock = (row, roleId) => {
    const r = ROLES.find(r => r.id === roleId);
    if (r && r.forced_on) return; // Admin is the only tier locked on
    const cur = getBlocks(row);
    const next = cur.includes(roleId) ? cur.filter(x => x !== roleId) : [...cur, roleId];
    setRowBlocks(row, next);
  };
  const bulkSetAllRoles = (row, block) => {
    const next = block
      ? ROLES.filter(r => !r.forced_on).map(r => r.id)
      : [];
    setRowBlocks(row, next);
  };

  const ALL_CURRENCIES = [
    { code:"EUR", symbol:"€", label:"Euro" },
    { code:"USD", symbol:"$", label:"US Dollar" },
    { code:"GBP", symbol:"£", label:"British Pound" },
    { code:"BRL", symbol:"R$", label:"Brazilian Real" },
    { code:"TRY", symbol:"₺", label:"Turkish Lira" },
    { code:"CAD", symbol:"C$", label:"Canadian Dollar" },
    { code:"MXN", symbol:"$", label:"Mexican Peso" },
    { code:"INR", symbol:"₹", label:"Indian Rupee" },
    { code:"ARS", symbol:"$", label:"Argentine Peso" },
    { code:"LBP", symbol:"ل.ل", label:"Lebanese Pound" },
    { code:"BOB", symbol:"Bs", label:"Bolivian Boliviano" },
    { code:"PYG", symbol:"₲", label:"Paraguayan Guaraní" },
  ];

  // Seed per-brand × per-method config (deterministic)
  const methodRows = [];
  BRANDS.forEach((b, bi) => {
    METHODS.forEach((m, mi) => {
      // Each skin is configured with exactly one currency (CMS → Skins), so
      // a method defaults to accepting only that currency. The Currencies
      // tab still lets an operator manually enable more for skins that
      // genuinely go multi-currency later.
      const currencies = [b.currency];
      methodRows.push({
        id: `${b.id}-${m.id}`,
        brand: b,
        method: m,
        enabled: !(bi === 2 && mi === 3),
        currencies,
        min: 10 + mi*5,
        max: 50000 + mi*5000,
        deposit_fee: (1 + mi*0.2).toFixed(2),
        withdraw_fee: (1.5 + mi*0.25).toFixed(2),
        success_rate: 98.4 - mi*0.8 - bi*0.2,
        volume_30d: Math.round(80000 + mi*25000 + bi*10000),
        auto_approve_under: 1500 - mi*100,
        auto_decline_under_kyc: true,
        review_threshold: 3000 + mi*500,
        rules_active: 3,
      });
    });
  });

  const mq = methodQuery.trim().toLowerCase();
  const filtered = methodRows.filter(r => {
    if (brandFilter !== "all" && r.brand.id !== brandFilter) return false;
    if (kindFilter !== "all" && r.method.kind !== kindFilter) return false;
    if (statusFilter === "enabled" && !r.enabled) return false;
    if (statusFilter === "disabled" && r.enabled) return false;
    if (currencyFilter !== "all" && !r.currencies.includes(currencyFilter)) return false;
    if (providerFilter !== "all") {
      const prov = rowProvider(r);
      if (!prov || !prov.chain.some(p => p.id === providerFilter)) return false;
    }
    if (mq) {
      const hay = [r.method.name, r.method.kind, r.brand.name, r.brand.short].join(" ").toLowerCase();
      if (!hay.includes(mq)) return false;
    }
    return true;
  });
  const anyMethodFilter = brandFilter !== "all" || kindFilter !== "all" || statusFilter !== "all" || currencyFilter !== "all" || providerFilter !== "all" || methodQuery !== "";
  const clearMethodFilters = () => {
    // Don't unlock the brand when the top-right selector is forcing the
    // page to a single brand — that's an auto-login, not a filter.
    if (brand && brand.isAll) setBrandFilter("all");
    setKindFilter("all"); setStatusFilter("all"); setCurrencyFilter("all"); setProviderFilter("all"); setMethodQuery("");
  };
  const METHOD_KINDS = Array.from(new Set(METHODS.map(m => m.kind)));
  const ALL_METHOD_CURRENCIES = Array.from(new Set(methodRows.flatMap(r => r.currencies))).sort();

  const getSymbol = (code) => (ALL_CURRENCIES.find(c=>c.code===code)?.symbol) || code;
  const fmtM = (n, cur) => `${getSymbol(cur)}${n.toLocaleString()}`;

  return (
    <div className="page">
      <div className="page__header">
        <div>
          <div className="page__title" style={{display:"inline-flex", alignItems:"center"}}>
            {T("page.methods","Payment methods")}
            <Tip>
              The catalog of every payment method offered to players, per brand. Each row is a unique <em>brand × method</em> configuration with its own currencies, fees, limits, auto-approval rules and role access. Expand a row to see the inline summary, or click Edit to open the full editor (General · Currencies · Fees · Limits · Roles · Auto-approval rules · PSP route).
            </Tip>
          </div>
          <div className="page__subtitle">Per-brand method configs · currencies, fees, limits and auto-approval rules</div>
        </div>
        <div className="page__actions">
          <button className="btn btn--secondary btn--sm"
            onClick={() => {
              if (!window.PAYBO) return;
              const stamp = new Date().toISOString().slice(0,10);
              const rows = methodRows.map(r => ({
                brand: r.brand.name, method: r.method.name, kind: r.method.kind,
                enabled: r.enabled ? "yes" : "no",
                currencies: r.currencies.join(" "),
                min: r.min, max: r.max,
                deposit_fee_pct: r.deposit_fee, withdraw_fee_pct: r.withdraw_fee,
                auto_approve_under: r.auto_approve_under,
                success_rate_30d: r.success_rate.toFixed(1),
                volume_30d: r.volume_30d,
              }));
              window.PAYBO.downloadCSV(`paybo-methods-${stamp}.csv`, rows, [
                { key:"brand", label:"brand" }, { key:"method", label:"method" },
                { key:"kind", label:"kind" }, { key:"enabled", label:"enabled" },
                { key:"currencies", label:"currencies" },
                { key:"min", label:"min" }, { key:"max", label:"max" },
                { key:"deposit_fee_pct", label:"deposit_fee_pct" },
                { key:"withdraw_fee_pct", label:"withdraw_fee_pct" },
                { key:"auto_approve_under", label:"auto_approve_under" },
                { key:"success_rate_30d", label:"success_rate_30d" },
                { key:"volume_30d", label:"volume_30d" },
              ]);
            }}>
            <Icon name="download" size={13}/> {T("btn.export","Export")}
          </button>
          <button className="btn btn--primary btn--sm"
            onClick={() => {
              // Open the standard editor pre-seeded with a blank row.
              const seedBrand = brand && !brand.isAll ? BRANDS.find(b => b.id === brand.id) || BRANDS[0] : BRANDS[0];
              setEditing({
                id: `new-${Date.now()}`,
                _new: true,
                brand: seedBrand,
                method: { id:"", name:"New method", color:"#1e40af", kind:"Card" },
                enabled: true,
                currencies: [seedBrand?.currency || "EUR"],
                min: 10, max: 50000,
                deposit_fee: "1.50", withdraw_fee: "1.75",
                success_rate: 0, volume_30d: 0,
                auto_approve_under: 1000, auto_decline_under_kyc: true,
                review_threshold: 3000, rules_active: 0,
                promo_code_enabled: true,
              });
            }}>
            <Icon name="plus" size={13}/> {T("btn.addMethod","Add method")}
          </button>
        </div>
      </div>

      <Explainer compact title="What this is, in plain English"
        bullets={[
          <><strong>Method</strong> — the payment instrument shown to the player (Visa, Mastercard, Apple Pay, Bank wire, Skrill, Crypto…).</>,
          <><strong>Provider</strong> — the PSP chain (Stripe → Adyen → Worldpay…) that processes a transaction of this method. Edited centrally in Settings → Routes &amp; cascading.</>,
          <><strong>Currencies</strong> — every accepted currency. Each one has its own Min / Max limits and its own fee overrides.</>,
          <><strong>Limits</strong> — money caps per period (Daily / Weekly / Monthly · Min / Max) and count caps (Number of deposits, failed deposits, withdrawals, failed withdrawals).</>,
          <><strong>Auto-approval</strong> — transactions at or below the threshold skip the manual review queue.</>,
        ]}>
        The master catalog of every payment method offered to players, per brand. Each row is a unique <em>brand × method</em> configuration; click <strong>Edit</strong> to open the full editor (General · Currencies · Fees · Limits · Roles · Auto-approval rules · PSP route).
      </Explainer>

      {/* Unified filter row — search / brand / kind / status / currency /
          provider / column visibility. The dedicated Brand chip row was
          removed: a single dropdown is consistent with the rest of the
          backoffice and works in the same auto-login pattern (locked
          when the top-right brand selector picks a single tenant). */}
      <div className="panel" style={{padding:"10px 14px", marginBottom:14, display:"flex", gap:10, alignItems:"center", flexWrap:"wrap"}}>
        <div style={{position:"relative", flex:"1 1 240px", maxWidth:360, display:"flex", alignItems:"center", background:"#fff", border:"1px solid var(--border-default)", borderRadius:10, boxShadow:"0 1px 2px rgba(15,20,32,.04)"}}>
          <Icon name="search" size={13} style={{position:"absolute", left:12, top:"50%", transform:"translateY(-50%)", color:"var(--text-tertiary)"}}/>
          <input value={methodQuery} onChange={e=>setMethodQuery(e.target.value)}
            placeholder={T("lbl.search","Search") + "…"}
            style={{width:"100%", border:"none", outline:"none", padding:"8px 12px 8px 34px", fontSize:12.5, background:"transparent", fontFamily:"inherit", borderRadius:10}}/>
        </div>

        {/* Brand filter — same dropdown shape as every other filter. When
            the top-right selector locks a brand we show a locked chip
            instead so the operator understands they're in auto-login mode. */}
        <div style={{background:"#fff", border:"1px solid var(--border-default)", borderRadius:10, padding:"4px 4px 4px 10px", display:"inline-flex", alignItems:"center", gap:6, boxShadow:"0 1px 2px rgba(15,20,32,.04)"}}>
          <Icon name="flag" size={12} style={{color:"var(--text-tertiary)"}}/>
          <span style={{fontSize:11.5, color:"var(--text-tertiary)", fontWeight:600}}>Brand</span>
          <Tip>Show only the methods configured for one brand. Hidden / locked when the top-right brand selector already picks a single tenant (it auto-logs you in to that tenant and overrides every per-page brand filter).</Tip>
          {brand && !brand.isAll ? (
            <span title="Locked by the top-right brand selector"
              style={{display:"inline-flex", alignItems:"center", gap:5, padding:"2px 8px", borderRadius:999, background:"var(--primary-soft, #eef2ff)", color:"var(--primary-dark, #1e3a8a)", fontSize:11.5, fontWeight:700}}>
              <Icon name="lock" size={10}/> {brand.name}
            </span>
          ) : (
            <select value={brandFilter} onChange={e=>setBrandFilter(e.target.value)}
              style={{border:"none", background:"transparent", fontSize:12.5, fontWeight:600, color:"var(--text-primary)", outline:"none", cursor:"pointer", padding:"4px 6px"}}>
              <option value="all">All brands</option>
              {BRANDS.map(b => <option key={b.id} value={b.id}>{b.name}</option>)}
            </select>
          )}
        </div>

        <div style={{background:"#fff", border:"1px solid var(--border-default)", borderRadius:10, padding:"4px 4px 4px 10px", display:"inline-flex", alignItems:"center", gap:6, boxShadow:"0 1px 2px rgba(15,20,32,.04)"}}>
          <Icon name="credit_card" size={12} style={{color:"var(--text-tertiary)"}}/>
          <span style={{fontSize:11.5, color:"var(--text-tertiary)", fontWeight:600}}>{T("lbl.kind","Kind")}</span>
          <Tip>Filter by the method family: Card, Wallet, Bank, Voucher, Crypto. Each kind has its own typical fees and settlement speed.</Tip>
          <select value={kindFilter} onChange={e=>setKindFilter(e.target.value)}
            style={{border:"none", background:"transparent", fontSize:12.5, fontWeight:600, color:"var(--text-primary)", outline:"none", cursor:"pointer", padding:"4px 6px"}}>
            <option value="all">{T("lbl.allKinds","All kinds")}</option>
            {METHOD_KINDS.map(k => <option key={k} value={k}>{k}</option>)}
          </select>
        </div>

        <div style={{background:"#fff", border:"1px solid var(--border-default)", borderRadius:10, padding:"4px 4px 4px 10px", display:"inline-flex", alignItems:"center", gap:6, boxShadow:"0 1px 2px rgba(15,20,32,.04)"}}>
          <Icon name="check" size={12} style={{color:"var(--text-tertiary)"}}/>
          <span style={{fontSize:11.5, color:"var(--text-tertiary)", fontWeight:600}}>{T("lbl.status","Status")}</span>
          <Tip><strong>Enabled</strong> rows accept new transactions. <strong>Disabled</strong> rows reject every new attempt but stay on file so you can re-enable later without losing the configuration.</Tip>
          <select value={statusFilter} onChange={e=>setStatusFilter(e.target.value)}
            style={{border:"none", background:"transparent", fontSize:12.5, fontWeight:600, color:"var(--text-primary)", outline:"none", cursor:"pointer", padding:"4px 6px"}}>
            <option value="all">{T("lbl.all","All")}</option>
            <option value="enabled">{T("lbl.enabled","Enabled")}</option>
            <option value="disabled">{T("lbl.disabled","Disabled")}</option>
          </select>
        </div>

        <div style={{background:"#fff", border:"1px solid var(--border-default)", borderRadius:10, padding:"4px 4px 4px 10px", display:"inline-flex", alignItems:"center", gap:6, boxShadow:"0 1px 2px rgba(15,20,32,.04)"}}>
          <Icon name="globe" size={12} style={{color:"var(--text-tertiary)"}}/>
          <span style={{fontSize:11.5, color:"var(--text-tertiary)", fontWeight:600}}>{T("lbl.currency","Currency")}</span>
          <Tip>Shows only methods that accept the selected currency. A single method can support several currencies — each tab in the editor sets its own limits / fees.</Tip>
          <select value={currencyFilter} onChange={e=>setCurrencyFilter(e.target.value)}
            style={{border:"none", background:"transparent", fontSize:12.5, fontWeight:600, color:"var(--text-primary)", outline:"none", cursor:"pointer", padding:"4px 6px"}}>
            <option value="all">{T("lbl.allCurrencies","All currencies")}</option>
            {ALL_METHOD_CURRENCIES.map(c => <option key={c} value={c}>{c}</option>)}
          </select>
        </div>

        <div style={{background:"#fff", border:"1px solid var(--border-default)", borderRadius:10, padding:"4px 4px 4px 10px", display:"inline-flex", alignItems:"center", gap:6, boxShadow:"0 1px 2px rgba(15,20,32,.04)"}}>
          <Icon name="globe" size={12} style={{color:"var(--text-tertiary)"}}/>
          <span style={{fontSize:11.5, color:"var(--text-tertiary)", fontWeight:600}}>Provider</span>
          <Tip>Limit to methods whose routing chain (Settings → Routes & cascading) contains the selected PSP at any position. Useful to spot which methods rely on a degraded or paused PSP.</Tip>
          <select value={providerFilter} onChange={e=>setProviderFilter(e.target.value)}
            style={{border:"none", background:"transparent", fontSize:12.5, fontWeight:600, color:"var(--text-primary)", outline:"none", cursor:"pointer", padding:"4px 6px"}}>
            <option value="all">All providers</option>
            {providers.map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
          </select>
        </div>

        {anyMethodFilter && (
          <button className="paybo-btn paybo-btn--ghost" style={{padding:"6px 10px"}} onClick={clearMethodFilters}>
            {T("btn.clearAll","Clear all")}
          </button>
        )}

        {/* Column-visibility popover — gear icon on the right edge of the
            filter row, matching the Transactions page pattern. */}
        <div style={{position:"relative", marginLeft:"auto", display:"inline-flex", alignItems:"center"}}>
          <button className="btn btn--ghost btn--sm" onClick={()=>setColsPopoverOpen(v => !v)}
            title="Show / hide columns" style={{display:"inline-flex", alignItems:"center", gap:6}}>
            <Icon name="settings" size={12}/> Columns
          </button>
          <Tip>Hide columns you don't need to free up table width. Brand, Method and Actions stay mandatory. Your layout is saved per operator (localStorage) so it sticks across sessions.</Tip>
          {colsPopoverOpen && (
            <>
              <div style={{position:"fixed", inset:0, zIndex:40}} onClick={()=>setColsPopoverOpen(false)}/>
              <div style={{position:"absolute", right:0, top:"calc(100% + 6px)", zIndex:50, background:"#fff", border:"1px solid var(--border-default)", borderRadius:10, boxShadow:"0 16px 32px -10px rgba(15,20,32,.25)", padding:"10px 12px", minWidth:200}}>
                <div style={{fontSize:11, fontWeight:700, color:"var(--text-tertiary)", textTransform:"uppercase", letterSpacing:".05em", marginBottom:8}}>Show columns</div>
                {METHOD_COLUMNS.map(c => (
                  <label key={c.key} style={{display:"flex", alignItems:"center", gap:8, padding:"4px 0", fontSize:12.5, cursor:"pointer"}}>
                    <input type="checkbox" checked={isColOn(c.key)} onChange={()=>toggleCol(c.key)} style={{accentColor:"var(--primary, #1e40af)"}}/>
                    {c.label}
                  </label>
                ))}
              </div>
            </>
          )}
        </div>
      </div>

      {/* Table */}
      <div className="panel" style={{overflow:"hidden"}}>
        <table className="data-table">
          <thead>
            <tr>
              <th style={{width:28}}></th>
              <th>Brand</th>
              <th>Method</th>
              {isColOn("provider")     && <th>Provider</th>}
              {isColOn("status")       && <th>Status</th>}
              {isColOn("currencies")   && <th>Currencies</th>}
              {isColOn("min_max")      && <th style={{textAlign:"right"}}>Min / Max</th>}
              {isColOn("dep_fee")      && <th style={{textAlign:"right"}}>Dep fee</th>}
              {isColOn("with_fee")     && <th style={{textAlign:"right"}}>With fee</th>}
              {isColOn("auto_approve") && <th style={{textAlign:"right"}}>Auto-approve&nbsp;≤</th>}
              <th style={{width:120}}></th>
            </tr>
          </thead>
          <tbody>
            {filtered.map(row => (
              <React.Fragment key={row.id}>
                <tr onClick={()=>setExpanded(expanded===row.id?null:row.id)} style={{cursor:"pointer"}} className={expanded===row.id?"selected":""}>
                  <td><Icon name={expanded===row.id?"chevron_down":"chevron_right"} size={12} style={{color:"var(--text-tertiary)"}}/></td>
                  <td>
                    <span style={{display:"inline-flex", alignItems:"center", gap:6}}>
                      <span style={{width:16, height:16, borderRadius:4, background:row.brand.color, color:"#fff", fontSize:9, fontWeight:700, display:"grid", placeItems:"center"}}>{row.brand.short}</span>
                      <span style={{fontSize:12.5}}>{row.brand.name}</span>
                    </span>
                  </td>
                  <td>
                    <span style={{display:"inline-flex", alignItems:"center", gap:8}}>
                      <span style={{width:8, height:8, borderRadius:2, background:row.method.color}}/>
                      <span style={{fontWeight:550}}>{row.method.name}</span>
                      <span className="chip chip--neutral" style={{fontSize:10}}>{row.method.kind}</span>
                    </span>
                  </td>
                  {isColOn("provider") && (() => {
                    const prov = window.lookupMethodProvider?.({ brand: row.brand, methodId: row.method.id, methodName: row.method.name });
                    return (
                      <td>
                        {prov ? (
                          <span style={{display:"inline-flex", alignItems:"center", gap:4, flexWrap:"wrap"}}>
                            {prov.chain.slice(0,3).map((p, i) => (
                              <React.Fragment key={p.id}>
                                <span style={{
                                  padding:"2px 8px", borderRadius:999,
                                  background: i === 0 ? "var(--p-50)" : "var(--n-25)",
                                  color: i === 0 ? "var(--p-700)" : "var(--text-secondary)",
                                  fontWeight:600, fontSize:10.5,
                                }}>{p.name}</span>
                                {i < Math.min(prov.chain.length, 3) - 1 && <span style={{color:"var(--text-tertiary)", fontSize:11}}>→</span>}
                              </React.Fragment>
                            ))}
                            {prov.chain.length > 3 && <span style={{fontSize:10.5, color:"var(--text-tertiary)"}}>+{prov.chain.length - 3}</span>}
                          </span>
                        ) : <span style={{fontSize:11, color:"var(--text-tertiary)"}}>—</span>}
                      </td>
                    );
                  })()}
                  {isColOn("status") && (
                    <td>
                      {row.enabled
                        ? <span className="chip chip--ok"><span className="dot" style={{background:"var(--ok-500)"}}/>Enabled</span>
                        : <span className="chip chip--neutral"><span className="dot" style={{background:"var(--n-400)"}}/>Disabled</span>}
                    </td>
                  )}
                  {isColOn("currencies") && (
                    <td>
                      <div style={{display:"flex", gap:3, flexWrap:"wrap"}}>
                        {row.currencies.map(c => (
                          <span key={c} className="chip chip--neutral" style={{fontSize:10.5, padding:"1px 6px", fontWeight:600}}>{c}</span>
                        ))}
                      </div>
                    </td>
                  )}
                  {isColOn("min_max")     && <td className="tnum" style={{textAlign:"right", fontSize:12}}>{fmtM(row.min, row.brand.currency)} — {fmtM(row.max, row.brand.currency)}</td>}
                  {isColOn("dep_fee")     && <td className="tnum" style={{textAlign:"right"}}>{row.deposit_fee}%</td>}
                  {isColOn("with_fee")    && <td className="tnum" style={{textAlign:"right"}}>{row.withdraw_fee}%</td>}
                  {isColOn("auto_approve")&& <td className="tnum" style={{textAlign:"right"}}>{fmtM(row.auto_approve_under, row.brand.currency)}</td>}
                  <td onClick={e=>e.stopPropagation()}>
                    <div style={{display:"flex", gap:4, justifyContent:"flex-end"}}>
                      <button className="btn btn--ghost btn--sm" onClick={()=>setEditing(row)}><Icon name="edit" size={12}/> Edit</button>
                      <NoBackend className="btn btn--ghost btn--icon btn--sm"
                        what={`Delete ${row.method.name}`}
                        need="the method-delete endpoint — destructive, and the row is shared across brands">
                        <Icon name="trash" size={12}/>
                      </NoBackend>
                    </div>
                  </td>
                </tr>
                {expanded === row.id && (
                  <tr>
                    <td colSpan={3 + METHOD_COLUMNS.filter(c => isColOn(c.key)).length + 1} style={{padding:0, background:"var(--n-25)"}}>
                      <div style={{padding:"16px 20px 0", display:"grid", gridTemplateColumns:"1.4fr 1fr", gap:20}}>
                        {/* General limits summary — read-only preview. Click
                            "Edit method" to adjust D/W/M min/max. */}
                        <div>
                          <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:10}}>
                            General limits — {row.brand.name} · {row.method.name} ({row.brand.currency})
                          </div>
                          <table className="data-table" style={{background:"var(--n-0)", border:"1px solid var(--border-default)", borderRadius:6, marginBottom:10}}>
                            <thead>
                              <tr>
                                <th></th>
                                <th colSpan={3} style={{textAlign:"center", borderRight:"1px solid var(--border-default)", fontSize:11.5}}>Minimum</th>
                                <th colSpan={3} style={{textAlign:"center", fontSize:11.5}}>Maximum</th>
                              </tr>
                              <tr>
                                <th></th>
                                <th style={{textAlign:"right", fontSize:11}}>Daily</th>
                                <th style={{textAlign:"right", fontSize:11}}>Weekly</th>
                                <th style={{textAlign:"right", fontSize:11, borderRight:"1px solid var(--border-default)"}}>Monthly</th>
                                <th style={{textAlign:"right", fontSize:11}}>Daily</th>
                                <th style={{textAlign:"right", fontSize:11}}>Weekly</th>
                                <th style={{textAlign:"right", fontSize:11}}>Monthly</th>
                              </tr>
                            </thead>
                            <tbody>
                              <tr>
                                <td>
                                  <span style={{display:"inline-flex", alignItems:"center", gap:6}}>
                                    <Icon name="arrow_down" size={12} style={{color:"var(--ok-600)"}}/>
                                    <strong>Deposit</strong>
                                  </span>
                                </td>
                                {[10, 10, 10].map((v, j) => (
                                  <td key={"dmin"+j} className="tnum" style={{textAlign:"right", borderRight: j===2?"1px solid var(--border-default)":"none"}}>{fmtM(v, row.brand.currency)}</td>
                                ))}
                                {[2000, 10000, 30000].map((v, j) => (
                                  <td key={"dmax"+j} className="tnum" style={{textAlign:"right"}}>{fmtM(v, row.brand.currency)}</td>
                                ))}
                              </tr>
                              <tr>
                                <td>
                                  <span style={{display:"inline-flex", alignItems:"center", gap:6}}>
                                    <Icon name="arrow_up" size={12} style={{color:"var(--purple-500)"}}/>
                                    <strong>Withdrawal</strong>
                                  </span>
                                </td>
                                {[20, 20, 20].map((v, j) => (
                                  <td key={"wmin"+j} className="tnum" style={{textAlign:"right", borderRight: j===2?"1px solid var(--border-default)":"none"}}>{fmtM(v, row.brand.currency)}</td>
                                ))}
                                {[3000, 15000, 45000].map((v, j) => (
                                  <td key={"wmax"+j} className="tnum" style={{textAlign:"right"}}>{fmtM(v, row.brand.currency)}</td>
                                ))}
                              </tr>
                            </tbody>
                          </table>
                        </div>
                        {/* Auto-approval quick view */}
                        <div>
                          <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:10}}>
                            Auto-approval rules
                          </div>
                          <div style={{background:"var(--n-0)", border:"1px solid var(--border-default)", borderRadius:6, padding:14, display:"flex", flexDirection:"column", gap:10}}>
                            <div style={{display:"flex", justifyContent:"space-between", alignItems:"center", fontSize:13}}>
                              <span style={{color:"var(--text-secondary)"}}>Auto-approve when amount ≤</span>
                              <strong className="tnum">{fmtM(row.auto_approve_under, row.brand.currency)}</strong>
                            </div>
                            <div style={{display:"flex", justifyContent:"space-between", alignItems:"center", fontSize:13}}>
                              <span style={{color:"var(--text-secondary)"}}>Manual review above</span>
                              <strong className="tnum">{fmtM(row.review_threshold, row.brand.currency)}</strong>
                            </div>
                            <div style={{display:"flex", justifyContent:"space-between", alignItems:"center", fontSize:13}}>
                              <span style={{color:"var(--text-secondary)"}}>Auto-decline if KYC pending</span>
                              <span className="chip chip--ok" style={{fontSize:10.5}}>ON</span>
                            </div>
                            <div style={{display:"flex", justifyContent:"space-between", alignItems:"center", fontSize:13}}>
                              <span style={{color:"var(--text-secondary)"}}>Custom rules</span>
                              <span className="chip chip--info" style={{fontSize:10.5}}>{row.rules_active} active</span>
                            </div>
                          </div>
                          <div style={{marginTop:12, display:"flex", gap:8}}>
                            <button className="btn btn--primary btn--sm" onClick={()=>setEditing({...row, _tab:"rules"})}><Icon name="sliders" size={12}/> Edit rules</button>
                            <button className="btn btn--ghost btn--sm" onClick={()=>setEditing(row)}><Icon name="edit" size={12}/> Edit method</button>
                          </div>
                        </div>
                      </div>

                      {/* Role access — bulk toggle which network tiers can use this method.
                          Only Admin is forced-on (platform-level operators always see
                          every method); every other tier can be turned off. */}
                      {(() => {
                        const blocks = getBlocks(row);
                        const blockedCount = blocks.length;
                        const togglableCount = ROLES.filter(r => !r.forced_on).length;
                        return (
                          <div style={{padding:"4px 20px 16px", borderBottom:"1px solid var(--border-default)"}}>
                            <div style={{display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:10}}>
                              <div>
                                <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)"}}>
                                  Role access — who can use {row.method.name} on {row.brand.short}
                                </div>
                                <div style={{fontSize:11.5, color:"var(--text-secondary)", marginTop:2}}>
                                  {blockedCount === 0
                                    ? "Available to every role in the network"
                                    : `${blockedCount} of ${togglableCount} roles blocked`}
                                </div>
                              </div>
                              <div style={{display:"flex", gap:6}}>
                                <button className="btn btn--ghost btn--sm" onClick={() => bulkSetAllRoles(row, false)}>Enable for all</button>
                                <button className="btn btn--ghost btn--sm" onClick={() => bulkSetAllRoles(row, true)}>Disable for all</button>
                              </div>
                            </div>
                            <div style={{
                              display:"grid",
                              gridTemplateColumns:"repeat(auto-fill, minmax(200px, 1fr))",
                              gap:8,
                              background:"var(--n-0)",
                              border:"1px solid var(--border-default)",
                              borderRadius:6,
                              padding:10,
                            }}>
                              {ROLES.map(r => {
                                const blocked = blocks.includes(r.id);
                                const forced = r.forced_on;
                                const on = forced || !blocked;
                                return (
                                  <div key={r.id} style={{
                                    display:"flex", alignItems:"center", gap:10,
                                    padding:"7px 10px", borderRadius:6,
                                    background: forced ? "var(--n-25)" : on ? "transparent" : "var(--err-50, #fee2e2)",
                                    border: "1px solid " + (forced ? "var(--border-subtle, #eef0f5)" : on ? "var(--border-subtle, #eef0f5)" : "var(--err-500)"),
                                    opacity: forced ? 0.82 : 1,
                                    cursor: forced ? "not-allowed" : "pointer",
                                  }} onClick={() => !forced && toggleRoleBlock(row, r.id)}>
                                    <span style={{width:10, height:10, borderRadius:3, background: r.color, flexShrink:0}}/>
                                    <span style={{flex:1, minWidth:0, fontSize:12.5, fontWeight:500}}>
                                      {r.label}
                                      {forced && <span style={{fontSize:10, color:"var(--text-tertiary)", marginLeft:6, fontWeight:400}}>locked</span>}
                                    </span>
                                    <span style={{
                                      width:28, height:16, borderRadius:999, position:"relative",
                                      background: on ? "var(--ok-500)" : "var(--n-400, #9ca3af)",
                                      transition:"background .12s", flexShrink:0,
                                    }}>
                                      <span style={{
                                        position:"absolute", top:2, left: on ? 14 : 2,
                                        width:12, height:12, borderRadius:999, background:"#fff",
                                        transition:"left .12s",
                                      }}/>
                                    </span>
                                  </div>
                                );
                              })}
                            </div>
                          </div>
                        );
                      })()}
                    </td>
                  </tr>
                )}
              </React.Fragment>
            ))}
          </tbody>
        </table>
      </div>

      {/* Edit modal */}
      {editing && <EditMethodModal editing={editing} setEditing={setEditing} ALL_CURRENCIES={ALL_CURRENCIES} getSymbol={getSymbol} fmtM={fmtM}/>}
    </div>
  );
};

/* ------------ Edit modal component ------------ */
const EditMethodModal = ({ editing, setEditing, ALL_CURRENCIES, getSymbol, fmtM }) => {
  const [tab, setTab] = useState(editing._tab || "general");
  const [currencies, setCurrencies] = useState(editing.currencies);
  const [activeCur, setActiveCur] = useState(editing.currencies[0]);

  /* Role access — local state seeded from METHOD_ROLE_BLOCKS (global per-
     method default); "blocked" means the role cannot use this method. */
  const MROLES = window.MOCK?.ROLES || [];
  const defaultRoleBlocks = window.MOCK?.METHOD_ROLE_BLOCKS?.[editing.method.id] || [];
  const [blockedRoles, setBlockedRoles] = useState(defaultRoleBlocks);
  const toggleRole = (roleId) => {
    const r = MROLES.find(x => x.id === roleId);
    if (r && r.forced_on) return; // Admin is the only tier locked on
    setBlockedRoles(prev => prev.includes(roleId) ? prev.filter(x => x !== roleId) : [...prev, roleId]);
  };
  const roleAllOn = () => setBlockedRoles([]);
  const roleAllOff = () => setBlockedRoles(MROLES.filter(r => !r.forced_on).map(r => r.id));

  const toggleCur = (code) => {
    setCurrencies(curs => {
      const next = curs.includes(code) ? curs.filter(c=>c!==code) : [...curs, code];
      if (!next.includes(activeCur) && next.length) setActiveCur(next[0]);
      return next;
    });
  };

  // editing.min/max/auto_approve_under are stored in the method's own brand
  // currency, not EUR — convert from that base into whichever currency chip
  // is active, rather than always pivoting off a raw EUR-per-unit table
  // (that treated every base value as if it were EUR, blowing up ARS/LBP/
  // BOB/PYG amounts by 3-5 orders of magnitude).
  const scale = (v) => Math.round(window.fxConvert(v, editing.brand.currency, activeCur));

  return (
    <div style={{position:"fixed", inset:0, background:"rgba(15,20,32,.4)", zIndex:100, display:"grid", placeItems:"center"}} onClick={()=>setEditing(null)}>
      <div className="panel" style={{width:920, maxHeight:"90vh", display:"flex", flexDirection:"column", padding:0, boxShadow:"var(--shadow-lg)"}} onClick={e=>e.stopPropagation()}>
        {/* Header */}
        <div style={{padding:"14px 18px", borderBottom:"1px solid var(--border-default)", display:"flex", alignItems:"center", gap:10}}>
          <span style={{width:22, height:22, borderRadius:5, background:editing.brand.color, color:"#fff", fontSize:10, fontWeight:700, display:"grid", placeItems:"center"}}>{editing.brand.short}</span>
          <div>
            <div style={{fontSize:11, color:"var(--text-tertiary)", textTransform:"uppercase", letterSpacing:".05em", fontWeight:600}}>Edit method · {editing.brand.name}</div>
            <div style={{fontSize:16, fontWeight:650, display:"flex", alignItems:"center", gap:10}}>
              <span style={{width:10, height:10, borderRadius:2, background:editing.method.color}}/>
              {editing.method.name}
              <span className="chip chip--neutral" style={{fontSize:10.5}}>{editing.method.kind}</span>
            </div>
          </div>
          <button className="btn btn--ghost btn--icon btn--sm" style={{marginLeft:"auto"}} onClick={()=>setEditing(null)}><Icon name="x" size={13}/></button>
        </div>

        {/* Tabs */}
        <div className="tabs" style={{padding:"0 18px", borderBottom:"1px solid var(--border-default)"}}>
          {[
            ["general","General","Status of the method, base-currency min / max, and whether it accepts deposits and / or withdrawals."],
            ["currencies",`Currencies · ${currencies.length}`,"Which currencies this method accepts on this brand. Each currency carries its own min / max overrides (fee overrides live in the Fees tab)."],
            ["fees","Fees","Deposit fee, withdrawal fee, and per-currency fee overrides charged by the operator on top of the PSP fee."],
            ["limits","Limits","Money limits per period (Daily / Weekly / Monthly · Min / Max) and count limits (Number of deposits, failed deposits, withdrawals, failed withdrawals) per period."],
            ["roles","Roles","Which network tiers (Master / Promoter / Agent / Player) are allowed to use this method. Admin is always on."],
            ["rules","Auto-approval rules","Conditions under which a deposit / withdrawal is auto-approved without operator review (e.g. amount ≤ €X, player is Gold, KYC complete)."],
            ["psp_route","PSP route","Which PSP chain is used to route transactions of this method, read-only — edited in Settings → Routes & cascading."],
          ].map(([k,label,hint])=>(
            <button key={k} className={tab===k?"active":""} onClick={()=>setTab(k)}
              style={{display:"inline-flex", alignItems:"center"}}>
              {label}
              <Tip>{hint}</Tip>
            </button>
          ))}
        </div>

        <div style={{padding:"18px 20px", overflow:"auto", flex:1}}>
          {/* ========= GENERAL ========= */}
          {tab === "general" && (
            <div style={{display:"flex", flexDirection:"column", gap:18}}>
              <Explainer compact title="What this is, in plain English">
                The <strong>{editing.method.name}</strong> method on <strong>{editing.brand.name}</strong>. This is the per-brand × per-method record the routing engine reads at transaction time. Set the display name shown to the player, toggle Status to enable / disable instantly, set base-currency Min / Max to clamp every transaction (per-currency caps live in the Currencies tab); pick whether Deposit and / or Withdrawal are allowed; decide whether players can apply a <em>Promo code</em> when paying with this method.
              </Explainer>
              <div>
                <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:10}}>Identity</div>
                <div style={{display:"grid", gridTemplateColumns:"2fr 1fr", gap:10, alignItems:"end"}}>
                  <div>
                    <label className="form-label">Method name<Tip>The display name shown to the player on the deposit / withdrawal page and used everywhere this method appears in the back office (routes, transactions, reports). Pick the official brand name of the instrument (e.g. "Visa", "Mastercard", "Apple Pay", "Bank wire", "Crypto · USDT").</Tip></label>
                    <input className="input input--sm" defaultValue={editing.method.name}
                      placeholder="e.g. Visa · Crypto · Bank wire"/>
                  </div>
                  <div>
                    <label className="form-label">Kind<Tip>The method family. Drives which PSPs can plausibly process this method (card processors only support Card, bank rails only support Bank, etc.).</Tip></label>
                    <select className="select input--sm" defaultValue={editing.method.kind || "Card"}>
                      <option>Card</option>
                      <option>Wallet</option>
                      <option>Bank</option>
                      <option>Voucher</option>
                      <option>Crypto</option>
                    </select>
                  </div>
                </div>
              </div>
              <div>
                <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:10}}>Status & amounts (base: {editing.brand.currency})</div>
                <div style={{display:"grid", gridTemplateColumns:"1fr 1fr 1fr", gap:10, alignItems:"end"}}>
                  <div>
                    <label className="form-label">Status<Tip>"Enabled" means the method accepts new transactions. "Disabled" stays on file but rejects every new attempt — useful for temporary pauses without losing the configuration.</Tip></label>
                    <div style={{padding:"6px 0"}}>
                      <Toggle defaultValue={editing.enabled} onLabel="Enabled" offLabel="Disabled"/>
                    </div>
                  </div>
                  <div><label className="form-label">Min (base)<Tip>Lower bound on the transaction amount, expressed in the brand's base currency ({editing.brand.currency}). The Currencies tab can override this per non-base currency.</Tip></label><input className="input input--sm" defaultValue={editing.min}/><CurrencyConversion amount={editing.min} currency={editing.brand.currency} divisor={1} suffix="" decimals={0}/></div>
                  <div><label className="form-label">Max (base)<Tip>Upper bound on the transaction amount, expressed in the brand's base currency. Transactions above this fail at validation, before they ever reach a PSP.</Tip></label><input className="input input--sm" defaultValue={editing.max}/><CurrencyConversion amount={editing.max} currency={editing.brand.currency} divisor={1} suffix="" decimals={0}/></div>
                </div>
              </div>
              <div>
                <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:10}}>Availability</div>
                <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:14}}>
                  <div>
                    <label className="form-label">Deposit<Tip>Allow players to deposit using this method. Turning this off blocks the method on the deposit page of the player frontend.</Tip></label>
                    <div style={{padding:"6px 0"}}><Toggle defaultValue={true}/></div>
                  </div>
                  <div>
                    <label className="form-label">Withdrawal<Tip>Allow players to cash out using this method. Withdrawals usually have stricter rules — e.g. KYC required, higher manual-review thresholds.</Tip></label>
                    <div style={{padding:"6px 0"}}><Toggle defaultValue={true}/></div>
                  </div>
                </div>
              </div>
              <div>
                <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:10}}>Promotions</div>
                <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:14}}>
                  <div>
                    <label className="form-label">
                      Promo code
                      <Tip>When this toggle is <strong>on</strong>, players can apply a promotion / bonus code when paying with this method. Use it to scope which methods are eligible for a campaign (e.g. enable on Visa &amp; Mastercard so a "first-deposit" bonus only fires on cards, not crypto). The toggle controls eligibility only — the actual campaigns are configured in <em>Bonus campaigns</em>. Turning it off here makes the promo-code field disappear from the deposit page of the player frontend for this method.</Tip>
                    </label>
                    <div style={{padding:"6px 0"}}>
                      <Toggle defaultValue={editing.promo_code_enabled !== false} onLabel="Allowed" offLabel="Disabled"/>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          )}

          {/* ========= CURRENCIES ========= */}
          {tab === "currencies" && (
            <div style={{display:"flex", flexDirection:"column", gap:18}}>
              <Explainer compact title="What this is, in plain English">
                Pick which currencies this method accepts on this brand. Each enabled currency exposes its own Min / Max (here) and its own deposit / withdrawal fee (in the Fees tab). Disabling a currency stops the method from appearing on the player frontend for that currency.
              </Explainer>
              <div>
                <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:4}}>Enabled currencies</div>
                <div style={{fontSize:12.5, color:"var(--text-secondary)", marginBottom:12}}>This method can accept transactions in any of the selected currencies. Each currency gets its own min/max overrides — fee overrides live in the Fees tab.</div>
                <div style={{display:"grid", gridTemplateColumns:"repeat(4, 1fr)", gap:8}}>
                  {ALL_CURRENCIES.map(c => {
                    const on = currencies.includes(c.code);
                    return (
                      <button key={c.code}
                        onClick={()=>toggleCur(c.code)}
                        className="panel"
                        style={{
                          padding:"10px 12px",
                          border: on?"1.5px solid var(--p-500)":"1px solid var(--border-default)",
                          background: on?"var(--p-50)":"var(--n-0)",
                          cursor:"pointer",
                          textAlign:"left",
                          display:"flex",
                          alignItems:"center",
                          gap:10,
                        }}>
                        <span style={{width:22, height:22, borderRadius:6, background:on?"var(--p-500)":"var(--n-75)", color:on?"#fff":"var(--text-secondary)", fontSize:11, fontWeight:700, display:"grid", placeItems:"center"}}>{c.symbol}</span>
                        <div style={{flex:1, minWidth:0}}>
                          <div style={{fontSize:12.5, fontWeight:600}}>{c.code}</div>
                          <div style={{fontSize:11, color:"var(--text-tertiary)", overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{c.label}</div>
                        </div>
                        <span style={{width:14, height:14, borderRadius:3, border:"1.5px solid " + (on?"var(--p-500)":"var(--border-strong)"), background:on?"var(--p-500)":"transparent", display:"grid", placeItems:"center"}}>
                          {on && <Icon name="check" size={9} style={{color:"#fff"}}/>}
                        </span>
                      </button>
                    );
                  })}
                </div>
              </div>

              {currencies.length > 0 && (
                <div>
                  <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:10}}>Per-currency overrides</div>
                  <div style={{display:"flex", gap:4, marginBottom:10, flexWrap:"wrap"}}>
                    {currencies.map(code => (
                      <button key={code} className={`filter-chip ${activeCur===code?"active":""}`} onClick={()=>setActiveCur(code)}>
                        <span style={{fontWeight:700}}>{getSymbol(code)}</span> {code}
                      </button>
                    ))}
                  </div>
                  <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:10}}>
                    <div><label className="form-label">Min amount</label><input key={`min-${activeCur}`} className="input input--sm" defaultValue={scale(editing.min)}/></div>
                    <div><label className="form-label">Max amount</label><input key={`max-${activeCur}`} className="input input--sm" defaultValue={scale(editing.max)}/></div>
                  </div>
                  <div style={{fontSize:11, color:"var(--text-tertiary)", marginTop:8}}>
                    Per-currency fee overrides live in the <strong style={{color:"var(--text-secondary)"}}>Fees</strong> tab.
                  </div>
                </div>
              )}
            </div>
          )}

          {/* ========= FEES ========= */}
          {tab === "fees" && (
            <div style={{display:"flex", flexDirection:"column", gap:18}}>
              <Explainer compact title="What this is, in plain English">
                The fee the operator charges on top of the PSP fee. Two parts: a <strong>percentage</strong> of the amount + a <strong>fixed</strong> flat charge per transaction. Effective fee = pct × amount + fixed. The <strong>Charged to</strong> dropdown decides whether the fee comes out of the player's balance (Player) or the operator's revenue (Operator).
              </Explainer>
              <div>
                <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:10}}>Base fees — applied unless per-currency override exists</div>
                <div style={{display:"grid", gridTemplateColumns:"1fr 1fr 1fr 1fr", gap:10}}>
                  <div><label className="form-label">Deposit fee %<Tip>Percentage taken on every successful deposit through this method. Common range: 0–3%. Set to 0 to absorb the cost.</Tip></label><input className="input input--sm" defaultValue={editing.deposit_fee}/></div>
                  <div><label className="form-label">Deposit fixed<Tip>Fixed amount added on top of the percentage, in the base currency. Useful for low-ticket methods where the % alone doesn't cover the PSP's flat fee.</Tip></label><input className="input input--sm" defaultValue="0.30"/></div>
                  <div><label className="form-label">Withdraw fee %<Tip>Percentage taken on every successful withdrawal. Usually higher than the deposit fee because operators want to discourage frequent low-value cash-outs.</Tip></label><input className="input input--sm" defaultValue={editing.withdraw_fee}/></div>
                  <div><label className="form-label">Withdraw fixed<Tip>Fixed amount added on top of the withdrawal percentage. Covers the PSP's per-payout charge.</Tip></label><input className="input input--sm" defaultValue="0.50"/></div>
                </div>
              </div>
              <div>
                <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:10}}>Fee recipient</div>
                <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:10}}>
                  <div><label className="form-label">Charged to<Tip><strong>Player</strong> = fee comes out of the player's balance (they see e.g. €100 deposit → €99 balance). <strong>Operator</strong> = the casino absorbs the fee out of its revenue (player sees €100 → €100).</Tip></label><select className="select input--sm"><option>Player</option><option>Operator</option></select></div>
                  <div><label className="form-label">Rounding<Tip>How fractional cents are handled when computing the fee. "Up to nearest 0.01" rounds half-cent-friendly; "Exact" keeps the raw float and surfaces a sub-cent figure where supported.</Tip></label><select className="select input--sm"><option>Up to nearest 0.01</option><option>Exact</option></select></div>
                </div>
              </div>
            </div>
          )}

          {/* ========= LIMITS =========
              Global per-method D/W/M min/max for deposit and withdrawal. */}
          {tab === "limits" && (
            <div style={{display:"flex", flexDirection:"column", gap:18}}>
              <Explainer compact title="What this is, in plain English"
                bullets={[
                  <><strong>General limits</strong> — money caps in this currency per period. Daily / Weekly / Monthly windows reset at 00:00 UTC. Max blocks transactions above the cap; Min blocks transactions below.</>,
                  <><strong>Count limits</strong> — how many transactions a player can make per period. Failed-count windows are useful for cards: a player whose Visa fails 5 times a day is usually doing fraud, not making a mistake.</>,
                ]}>
                Both money limits and count limits live here. Money limits are per currency (switch with the chips below); count limits are global per method. Crossing a limit blocks the next transaction on that method.
              </Explainer>
              <div style={{display:"flex", alignItems:"center", gap:10}}>
                <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)"}}>Limits in</div>
                <Tip>Switch the active currency tab to view / edit limits for that currency. Each currency keeps its own min / max per period.</Tip>
                <div style={{display:"flex", gap:4}}>
                  {currencies.map(code => (
                    <button key={code} className={`filter-chip ${activeCur===code?"active":""}`} onClick={()=>setActiveCur(code)}>
                      <span style={{fontWeight:700}}>{getSymbol(code)}</span> {code}
                    </button>
                  ))}
                </div>
              </div>

              {/* General D/W/M min/max — applies to every account on this method. */}
              <div>
                <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:10}}>
                  General limits — {editing.method.name} on {editing.brand.name} · {activeCur}
                </div>
                <table className="data-table" style={{border:"1px solid var(--border-default)", borderRadius:6}}>
                  <thead>
                    <tr>
                      <th></th>
                      <th colSpan={3} style={{textAlign:"center", borderRight:"1px solid var(--border-default)"}}>Minimum</th>
                      <th colSpan={3} style={{textAlign:"center"}}>Maximum</th>
                    </tr>
                    <tr>
                      <th></th>
                      <th style={{textAlign:"center", fontSize:11}}>Daily</th>
                      <th style={{textAlign:"center", fontSize:11}}>Weekly</th>
                      <th style={{textAlign:"center", fontSize:11, borderRight:"1px solid var(--border-default)"}}>Monthly</th>
                      <th style={{textAlign:"center", fontSize:11}}>Daily</th>
                      <th style={{textAlign:"center", fontSize:11}}>Weekly</th>
                      <th style={{textAlign:"center", fontSize:11}}>Monthly</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>
                        <span style={{display:"inline-flex", alignItems:"center", gap:6, fontWeight:600}}>
                          <Icon name="arrow_down" size={12} style={{color:"var(--ok-600)"}}/> Deposit
                        </span>
                      </td>
                      {[10, 10, 10].map((v, j) => (
                        <td key={"dmin"+j} style={{padding:"4px 6px", borderRight: j===2 ? "1px solid var(--border-default)" : "none"}}>
                          <input key={`dmin${j}-${activeCur}`} className="input input--sm" style={{width:100, fontSize:11.5, padding:"3px 6px"}} defaultValue={scale(v)}/>
                        </td>
                      ))}
                      {[2000, 10000, 30000].map((v, j) => (
                        <td key={"dmax"+j} style={{padding:"4px 6px"}}>
                          <input key={`dmax${j}-${activeCur}`} className="input input--sm" style={{width:100, fontSize:11.5, padding:"3px 6px"}} defaultValue={scale(v)}/>
                        </td>
                      ))}
                    </tr>
                    <tr>
                      <td>
                        <span style={{display:"inline-flex", alignItems:"center", gap:6, fontWeight:600}}>
                          <Icon name="arrow_up" size={12} style={{color:"var(--purple-500)"}}/> Withdrawal
                        </span>
                      </td>
                      {[20, 20, 20].map((v, j) => (
                        <td key={"wmin"+j} style={{padding:"4px 6px", borderRight: j===2 ? "1px solid var(--border-default)" : "none"}}>
                          <input key={`wmin${j}-${activeCur}`} className="input input--sm" style={{width:100, fontSize:11.5, padding:"3px 6px"}} defaultValue={scale(v)}/>
                        </td>
                      ))}
                      {[3000, 15000, 45000].map((v, j) => (
                        <td key={"wmax"+j} style={{padding:"4px 6px"}}>
                          <input key={`wmax${j}-${activeCur}`} className="input input--sm" style={{width:100, fontSize:11.5, padding:"3px 6px"}} defaultValue={scale(v)}/>
                        </td>
                      ))}
                    </tr>
                  </tbody>
                </table>
                <div style={{fontSize:11.5, color:"var(--text-tertiary)", marginTop:6}}>Values shown in {activeCur}. Switch currency above to edit per-currency limits.</div>
              </div>

              {/* Count limits — per period (daily / weekly / monthly).
                  Includes both successful and FAILED counts so the engine
                  can throttle a player who keeps retrying a busted card. */}
              <div>
                <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:10}}>
                  Count limits — number of transactions per period
                </div>
                <table className="data-table" style={{border:"1px solid var(--border-default)", borderRadius:6}}>
                  <thead>
                    <tr>
                      <th></th>
                      <th style={{textAlign:"center", fontSize:11}}>Daily</th>
                      <th style={{textAlign:"center", fontSize:11}}>Weekly</th>
                      <th style={{textAlign:"center", fontSize:11}}>Monthly</th>
                    </tr>
                  </thead>
                  <tbody>
                    {[
                      { id:"n_deposits",         label:"Number of deposits",          icon:"arrow_down", color:"var(--ok-600)",     def:[20, 60, 200] },
                      { id:"n_failed_deposits",  label:"Number of failed deposits",   icon:"x",          color:"var(--err-600)",    def:[5,  15,  40]  },
                      { id:"n_withdrawals",      label:"Number of withdrawals",       icon:"arrow_up",   color:"var(--purple-500)", def:[5,  15,  50]  },
                      { id:"n_failed_withdrawals",label:"Number of failed withdrawals",icon:"x",         color:"var(--err-600)",    def:[3,  10,  25]  },
                    ].map(row => (
                      <tr key={row.id}>
                        <td>
                          <span style={{display:"inline-flex", alignItems:"center", gap:6, fontWeight:600}}>
                            <Icon name={row.icon} size={12} style={{color: row.color}}/> {row.label}
                          </span>
                        </td>
                        {row.def.map((v, j) => (
                          <td key={`${row.id}-${j}`} style={{padding:"4px 6px"}}>
                            <input type="number" min={0} className="input input--sm" style={{width:100, fontSize:11.5, padding:"3px 6px"}} defaultValue={v}/>
                          </td>
                        ))}
                      </tr>
                    ))}
                  </tbody>
                </table>
                <div style={{fontSize:11.5, color:"var(--text-tertiary)", marginTop:6, lineHeight:1.5}}>
                  Failed-count windows are useful for cards: a player whose Visa fails 5 times in a day is usually doing fraud, not making a mistake. Crossing a count limit blocks the next transaction on that method.
                </div>
              </div>
            </div>
          )}

          {/* ========= ROLES =========
              Per-method bulk toggle: which network tiers can use this
              method. Only Admin is forced-on. Master, Promoter, Agent,
              through Player each flip independently. */}
          {tab === "roles" && (
            <div style={{display:"flex", flexDirection:"column", gap:14}}>
              <Explainer compact title="What this is, in plain English">
                Which network tiers can use this method on this brand. The White Label pyramid is <strong>Admin → Master → Promoter → Agent → Player</strong>. Admin is always on; every other tier can be toggled. Blocking a tier also blocks every tier under it (e.g. blocking Agent also blocks Player accounts under that Agent).
              </Explainer>
              <div style={{display:"flex", alignItems:"flex-start", justifyContent:"space-between", gap:10}}>
                <div>
                  <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)"}}>
                    Role access — {editing.method.name} on {editing.brand.short}
                  </div>
                  <div style={{fontSize:12.5, color:"var(--text-secondary)", marginTop:4}}>
                    Turn the method on or off for each tier of the White Label pyramid.
                    Admin is always on — every other tier can be toggled.
                  </div>
                </div>
                <div style={{display:"flex", gap:6, flexShrink:0}}>
                  <button className="btn btn--ghost btn--sm" onClick={roleAllOn}>Enable for all</button>
                  <button className="btn btn--ghost btn--sm" onClick={roleAllOff}>Disable for all</button>
                </div>
              </div>
              <div style={{display:"grid", gridTemplateColumns:"repeat(auto-fill, minmax(240px, 1fr))", gap:8, padding:10, background:"var(--n-0)", border:"1px solid var(--border-default)", borderRadius:6}}>
                {MROLES.map(r => {
                  const blocked = blockedRoles.includes(r.id);
                  const forced = r.forced_on;
                  const on = forced || !blocked;
                  return (
                    <div key={r.id}
                      style={{
                        display:"flex", alignItems:"center", gap:12,
                        padding:"9px 12px", borderRadius:6,
                        background: forced ? "var(--n-25)" : on ? "transparent" : "var(--err-50, #fee2e2)",
                        border: "1px solid " + (forced ? "var(--border-subtle, #eef0f5)" : on ? "var(--border-subtle, #eef0f5)" : "var(--err-500)"),
                        cursor: forced ? "not-allowed" : "pointer",
                      }}
                      onClick={() => !forced && toggleRole(r.id)}>
                      <span style={{width:10, height:10, borderRadius:3, background: r.color, flexShrink:0}}/>
                      <div style={{flex:1, minWidth:0}}>
                        <div style={{fontSize:13, fontWeight:600}}>
                          {r.label}
                          {forced && <span style={{fontSize:10, color:"var(--text-tertiary)", marginLeft:6, fontWeight:400}}>locked on</span>}
                        </div>
                        <div style={{fontSize:11, color:"var(--text-tertiary)", overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{r.desc}</div>
                      </div>
                      <Toggle value={on} disabled={forced} size="sm" label=""/>
                    </div>
                  );
                })}
              </div>
              <div style={{fontSize:11.5, color:"var(--text-tertiary)"}}>
                {blockedRoles.length === 0
                  ? "Available to every role in the network."
                  : `${blockedRoles.length} of ${MROLES.filter(r => !r.forced_on).length} togglable roles blocked.`}
              </div>
            </div>
          )}

          {/* ========= RULES ========= */}
          {tab === "rules" && (
            <div style={{display:"flex", flexDirection:"column", gap:18}}>
              <Explainer compact title="What this is, in plain English">
                Conditions under which a transaction skips the manual-review queue and gets approved automatically. The simplest rule is an <strong>amount threshold</strong>: everything at or below the threshold auto-approves; everything above it lands in To-Confirm for an operator to look at. Stricter rules (KYC complete, player Gold-tier, country allowlist) can be layered on the same record in v2. On a multi-currency method each enabled currency keeps its own threshold — switch the chip below to set it per currency, same as Limits.
              </Explainer>
              {currencies.length > 1 && (
                <div style={{display:"flex", alignItems:"center", gap:10}}>
                  <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)"}}>Threshold in</div>
                  <div style={{display:"flex", gap:4}}>
                    {currencies.map(code => (
                      <button key={code} className={`filter-chip ${activeCur===code?"active":""}`} onClick={()=>setActiveCur(code)}>
                        <span style={{fontWeight:700}}>{getSymbol(code)}</span> {code}
                      </button>
                    ))}
                  </div>
                </div>
              )}
              <div style={{padding:"10px 14px", border:"1px solid var(--border-default)", borderRadius:6, display:"flex", alignItems:"center", gap:14}}>
                <div style={{flex:1}}>
                  <div style={{fontSize:12, fontWeight:600, marginBottom:2, display:"flex", alignItems:"center"}}>General auto-approve threshold<Tip>Transactions whose amount is at or below this value skip the manual-review queue entirely and are recorded as Balanced (deposits) or sent to the PSP (withdrawals) immediately. Above the threshold the transaction lands in To-Confirm for an operator to approve or reject.</Tip></div>
                  <div style={{fontSize:11.5, color:"var(--text-tertiary)"}}>Transactions at or below this amount skip manual review.</div>
                </div>
                <div>
                  <div style={{display:"flex", alignItems:"center", gap:8}}>
                    <input key={activeCur} className="input input--sm" style={{width:140}} defaultValue={scale(editing.auto_approve_under)}/>
                    <span style={{fontSize:11.5, color:"var(--text-tertiary)", fontWeight:600}}>{activeCur}</span>
                  </div>
                  <CurrencyConversion amount={scale(editing.auto_approve_under)} currency={activeCur} divisor={1} suffix="" decimals={0}/>
                </div>
              </div>
            </div>
          )}

          {/* ========= PSP ROUTE ========= */}
          {tab === "psp_route" && (() => {
            const all = window.MOCK_ROUTES || [];
            const matches = all.filter(r =>
              (r.method === editing.method.name || r.method === "any") &&
              (r.brand === editing.brand.name || r.brand === "any")
            );
            return (
              <div style={{display:"flex", flexDirection:"column", gap:14}}>
                <Explainer compact title="What this is, in plain English">
                  Read-only view of which PSP chain processes this method on this brand. The chain (1st PSP → 2nd → 3rd) is the operator's ranking; on failure the engine cascades to the next position. Routes are edited centrally in <strong>Settings → Routes &amp; cascading</strong> — same record, just surfaced here so you can audit it from inside the method.
                </Explainer>
                <div>
                  <div style={{fontSize:11, fontWeight:600, textTransform:"uppercase", letterSpacing:".05em", color:"var(--text-tertiary)", marginBottom:4}}>PSP route</div>
                  <div style={{fontSize:12.5, color:"var(--text-secondary)"}}>
                    Read-only view of the provider chains that apply to <strong>{editing.method.name}</strong> on <strong>{editing.brand.name}</strong>. Edit these in <strong>Settings → Routes &amp; cascading</strong>.
                  </div>
                </div>
                {matches.length === 0 ? (
                  <div style={{padding:"14px 16px", border:"1px dashed var(--border-default)", borderRadius:6, fontSize:12.5, color:"var(--text-tertiary)"}}>
                    No routes configured for this method on this brand yet. Add one in <strong>Settings → Routes &amp; cascading</strong>.
                  </div>
                ) : (
                  <table className="data-table" style={{border:"1px solid var(--border-default)", borderRadius:6}}>
                    <thead>
                      <tr>
                        <th>Scope</th>
                        <th>Currency</th>
                        <th>Amount band</th>
                        <th>Provider chain</th>
                        <th>Cascade triggers</th>
                        <th>Mode</th>
                        <th>Status</th>
                      </tr>
                    </thead>
                    <tbody>
                      {matches.map(r => (
                        <tr key={r.id}>
                          <td style={{fontSize:12}}>{r.brand === "any" ? "All brands" : r.brand}</td>
                          <td><span className="chip chip--neutral" style={{fontSize:10.5}}>{r.currency === "any" ? "Any" : r.currency}</span></td>
                          <td style={{fontSize:12}}>{r.amount}</td>
                          <td>
                            <div style={{display:"flex", gap:4, flexWrap:"wrap"}}>
                              {r.chain.map((p, i) => (
                                <React.Fragment key={p}>
                                  <span className="chip" style={{background:"var(--p-50)", color:"var(--p-700)", fontSize:10.5, fontWeight:600}}>{p}{r.weighted && r.weights[i] != null ? ` · ${r.weights[i]}%` : ""}</span>
                                  {i < r.chain.length - 1 && <span style={{color:"var(--text-tertiary)", fontSize:11}}>→</span>}
                                </React.Fragment>
                              ))}
                            </div>
                          </td>
                          <td style={{fontSize:11.5, color:"var(--text-secondary)"}}>{r.triggers.join(", ")}</td>
                          <td><span className="chip chip--neutral" style={{fontSize:10.5}}>{r.mode}</span></td>
                          <td>
                            {r.status === "active"
                              ? <span className="chip chip--ok" style={{fontSize:10.5}}>Active</span>
                              : <span className="chip chip--neutral" style={{fontSize:10.5}}>Paused</span>}
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                )}
              </div>
            );
          })()}
        </div>

        {/* Footer */}
        <div style={{padding:"12px 18px", borderTop:"1px solid var(--border-default)", background:"var(--n-25)", display:"flex", gap:8, alignItems:"center"}}>
          <NoBackend className="btn btn--danger btn--sm"
            what="Delete method"
            need="the method-delete endpoint — destructive, and the row is shared across brands">
            <Icon name="trash" size={12}/> {T("btn.deleteMethod","Delete method")}
          </NoBackend>
          <div style={{marginLeft:"auto", display:"flex", gap:8}}>
            <button className="btn btn--secondary btn--sm" onClick={()=>setEditing(null)}>{T("btn.cancel","Cancel")}</button>
            <button className="btn btn--primary btn--sm"
              onClick={() => {
                if (window.PAYBO?.emitToast) {
                  window.PAYBO.emitToast({
                    id: `save-${editing.id}-${Date.now()}`,
                    tx_id: `Saved ${editing.method.name}`,
                    amount: 0, currency: "DEMO",
                    player: editing.brand.name,
                    reason: `Updated ${blockedRoles.length} role block${blockedRoles.length===1?"":"s"}, ${currencies.length} currencies.`,
                  });
                }
                setEditing(null);
              }}>
              <Icon name="check" size={12}/> {T("btn.save","Save changes")}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};

window.Methods = Methods;
