// NO PROD JSON API (bucket C) — mock until backend (see PROD_API_INVENTORY.md)
// Represents: GET /withdraw/myrequests · WithdrawController — see docs/ISYSTEM_REFERENCE.md §Batch 2 "My withdrawal requests"
/* ====================================================================
   MY WITHDRAWAL REQUESTS — Report ▾ rebuild (Batch 2), Hrs* shell
   ====================================================================
   Real screen: `GET /withdraw/myrequests/` (unnamed route, routes/admin.php
   L882-884) → WithdrawController::myRequests (L15-27, builds $table_columns
   only) + static WithdrawController::getMyRequests (L29-280, DataTables JSON,
   $is_frontend=0). Status enum App\Constants\WithdrawRequestStatus; labels /
   row classes via WithdrawRequestsController::requestsStatus (L506) and
   getRichiestaPrelievoClass (L523). Blade admin/withdraw/myrequests.blade.php
   + public/js/pages/withdraw/myrequests.js.

   OPERATOR-AS-REQUESTER: rows are hard-scoped `withdrawal_requests.userid =
   Auth::user()->id` (L194) — the operator's OWN requests, NOT the network
   approval queue (that is HostWithdraws.jsx / WithdrawRequestsController,
   `/withdrawrequests`, which shares the same table).

   Faithful absences (nothing added — brief §3):
   - NO filters: the blade renders no filter inputs; myrequests.js wires
     #kt_search/.kt-input handlers to elements that don't exist. Server-side
     per-column search exists but is unreachable from this page — and its
     `request_status` branch hardcodes status 0 whatever value is sent
     (L119-121), `CashingTime` never matches the sent `chasingTime`.
     // <!-- SUGGESTION: the server already supports per-column search (id,
     //      method, description LIKE, amount min|max, date range) — surface a
     //      small filter bar, and fix the request_status branch that ignores
     //      its value and hardcodes Pending. -->
   - NO export: DataTables Buttons/pdfmake are loaded from public CDNs
     (myrequests.blade.php L82-88) but no buttons are configured in `dom`.
     // <!-- SUGGESTION: drop the unused CDN bundles or configure a real
     //      export button — today the page ships the libraries for nothing. -->
   - NO row actions: the cancel button (visualizzaModalEliminazione, 8h window
     while Pending) is only emitted when $is_frontend == 1 — the player-
     frontend twin (WithdrawFrontendController::getMyRequests, web.php L411).
     No invented Cancel here.
   - NO KPIs/totals: $totalBank/$totalPix are initialized (L205-206) and never
     used.

   Divergences implemented as evident intent (known-bug policy):
   1. Result date sorting — the server order-switch handles "CashingTime" but
      the column sends "chasingTime" (DB column "ChasingTime"): the triple
      spelling kills Result-date ordering on the live platform. Sortable here.
      // <!-- SUGGESTION: unify chasingTime/CashingTime/ChasingTime so the
      //      Result date column can actually sort (and its range search work). -->
   2. CANCELED rows — the real player self-cancel writes REJECTED(2) instead
      of CANCELED(4) (known platform bug, see build policies), yet this very
      screen special-cases request_status == 4 to swap the Description cell to
      backend.cancelled_by_customer ("Canceled by the customer", L235-239).
      Mock data models the intent: canceled rows carry status 4.
      // <!-- SUGGESTION: make the cancel flow write CANCELED(4) so the
      //      cancelled_by_customer branch this page already ships can fire. -->

   Creation flow (documented, not built — the reference stops at the fields):
   `GET /withdraw/` lists methods with skin_withdraw_methods.bo_status = 1 →
   `GET /withdraw/{method}` (bank / pix / crypto form) → AJAX
   `POST /withdraw/doWithdraw` → WithdrawRequest::create() (status 0/PENDING)
   then the balance is debited IMMEDIATELY via raw SQL (tempChangeBalanceUser).
   The sidebar has no link to `/withdraw/` — URL-only entry (UNCLEAR in the
   reference whether operators are expected to navigate there manually), so
   this rebuild explains the entry point instead of inventing a "New request"
   button the real screen doesn't have. `/withdraw/withdrawok/{method}` is
   dead (no such controller method; paymentok → nonexistent view).
   // <!-- SUGGESTION: link the creation flow (`/withdraw/`) from this screen
   //      or the sidebar — today operators must type the URL by hand. -->

   Demo session = Super admin "admin" (level 0), currency ARS — matching the
   other Host screens' persona. All names hrmw/Hrmw/HRMW-prefixed except the
   required page component `WithdrawalRequests` (app.jsx case
   "report-withdrawals"; this file loads after HostReports.jsx so this
   definition wins over the legacy stub).
   ==================================================================== */

const { useState: hrmwUseState, useMemo: hrmwUseMemo } = React;

/* ---------- WithdrawRequestStatus (app/Constants/WithdrawRequestStatus.php)
   Labels per requestsStatus(): 0→"Pending" (backend.request_status_pending),
   1→"Approved", 2→"Rejected", 3→hardcoded 'Error' (no lang key),
   4→"Canceled". The phantom "5 → UNDEFINED" (no such DB value) is not
   represented. Chip tones map the real row classes pending-w / approved-w /
   declined-w / error-w / annulled-w onto the theme's existing .chip set
   (error-w darkened inline to stay distinct from declined-w). ---------- */
const HRMW_STATUS = {
  0: { label: "Pending",  chip: "chip--warn" },                 // pending-w
  1: { label: "Approved", chip: "chip--ok" },                   // approved-w
  2: { label: "Rejected", chip: "chip--err" },                  // declined-w
  3: { label: "Error",    chip: "chip--err", dark: true },      // error-w — hardcoded 'Error', no lang key
  4: { label: "Canceled", chip: "chip--neutral" },              // annulled-w
};

const HrmwChip = ({ s }) => {
  const st = HRMW_STATUS[s] || { label: "UNDEFINED", chip: "chip--err", dark: true }; // real default branch: 'UNDEFINED' / error-w
  return (
    <span className={`chip ${st.chip}`} style={st.dark ? { background: "var(--err-700)", color: "#fff", borderColor: "transparent" } : undefined}>
      {st.label}
    </span>
  );
};

const hrmwPad = (n) => String(n).padStart(2, "0");
/* PHP `d/m/Y G:i` — padded day/month, hour WITHOUT leading zero, padded minutes. */
const hrmwDT = (ts) => {
  const d = new Date(ts);
  return `${hrmwPad(d.getDate())}/${hrmwPad(d.getMonth() + 1)}/${d.getFullYear()} ${d.getHours()}:${hrmwPad(d.getMinutes())}`;
};

/* HRMW_DECLINES and HRMW_ERRORS lived here: five plausible decision notes the
   generator picked from to fill the Description column. They read as real
   compliance decisions about a real person's payout, which is exactly why they
   are gone rather than kept "as examples". The column now shows
   withdrawal_requests.decision_note, and shows nothing when there is none. */

/* This screen used to build its 27 rows here: a seeded generator producing
   amounts, statuses, decision notes, two IBANs, a CPF that passes the real
   mod-11 check, and two crypto wallet addresses. It is gone. Payout
   destinations that look real are the worst thing to invent on a screen about
   somebody's own money — they are indistinguishable from a record.

   The row shape below is what the table renders; it is now built from
   withdrawal_requests. isystem spread the destination across
   iban/swift/cpf/pix_key/crypto_wallet/crypto_coin columns; here it is one
   `payout_details` jsonb, so the three Request-data variants read from one
   place instead of six nullable columns. */
const hrmwFromRow = (r) => {
  const d = (r && r.payout_details) || {};
  /* isystem branches the Request-data cell on which columns are populated.
     With one jsonb column the branch is on what the object carries — same
     three shapes, one source. */
  const method = d.crypto_wallet || d.coin ? "crypto"
    : d.pix_key || d.cpf ? "pix"
    : d.iban ? "bank"
    : (r.method && r.method.code) || "—";
  return {
    id: r.id,
    addedTime: r.created_at ? Date.parse(r.created_at) : 0,
    amount: Number(r.amount || 0),
    currency: r.currency,
    method,
    status: Number(r.status_id),
    /* isystem's chasingTime. Null while Pending — the column renders "—". */
    chasingTime: r.decided_at ? Date.parse(r.decided_at) : null,
    answer: r.decision_note || "",
    iban: d.iban || null,
    cpf: d.cpf || null,
    pixKey: d.pix_key || null,
    coin: d.coin || null,
    wallet: d.crypto_wallet || null,
  };
};

/* ---------- Request data cell — computed HTML per method (L211-224):
   bank → method + IBAN; pix → method + CPF + PIX-KEY; crypto → method + COIN
   + Address; anything else → empty. (Header is bound to DataTables name
   `request_type` — mismatched semantics on the real screen, noted only.) */
const hrmwReqData = (r) => {
  const line = { fontSize: 11.5, color: "var(--text-secondary)", overflowWrap: "anywhere" };
  if (r.method === "bank") return (
    <div style={{ display: "grid", gap: 1 }}><b>bank</b><span style={line}>IBAN: {r.iban}</span></div>
  );
  if (r.method === "pix") return (
    <div style={{ display: "grid", gap: 1 }}><b>pix</b><span style={line}>CPF: {r.cpf}</span><span style={line}>PIX-KEY: {r.pixKey}</span></div>
  );
  if (r.method === "crypto") return (
    <div style={{ display: "grid", gap: 1 }}><b>crypto</b><span style={line}>COIN: {r.coin}</span><span style={line}>Address: {r.wallet}</span></div>
  );
  return "";
};

/* Description cell: answer_description, replaced by backend.cancelled_by_customer
   ("Canceled by the customer") whenever request_status == 4 (L235-239). */
const hrmwDescription = (r) => r.status === 4 ? "Canceled by the customer" : (r.answer || "");

/* Of the visible columns only Date, Amount, Request status actually sort on
   the live platform; Result date is sortable here as evident intent (see
   header divergence 1); Description / Method / Request data have no server
   order branch at all → non-sortable, faithfully. */
const HRMW_SORTERS = {
  addedTime: (r) => r.addedTime,
  amount: (r) => r.amount,
  status: (r) => r.status,
  chasingTime: (r) => r.chasingTime || 0,
};

const HRMW_COLUMNS = [
  { key: "addedTime", label: "Date", sortable: true, width: 128, render: (r) => hrmwDT(r.addedTime) },
  { key: "amount", label: "Amount", align: "right", sortable: true, render: (r) => hrsMoney(r.amount, r.currency) },
  { key: "status", label: "Request status", align: "center", sortable: true, render: (r) => <HrmwChip s={r.status} /> },
  { key: "chasingTime", label: "Result date", sortable: true, width: 128, render: (r) => r.chasingTime ? hrmwDT(r.chasingTime) : "" },
  { key: "description", label: "Description", render: hrmwDescription },
  { key: "method", label: "Method", render: (r) => r.method },
  { key: "reqdata", label: "Request data", render: hrmwReqData },
];

/* ==================================================================
   Page component — name required by app.jsx ("report-withdrawals").
   Loads after the legacy HostReports.jsx stub, so this wins.
   ================================================================== */
const WithdrawalRequests = () => {
  window.useLocale && window.useLocale();
  /* JS initial order [[0,"desc"]] → Date desc (server fallback: id DESC). */
  const [sort, setSort] = hrmwUseState({ key: "addedTime", dir: "desc" });
  /* pageLength 100, lengthMenu [5,10,25,50,100] (myrequests.js L18). */
  const [page, setPage] = hrmwUseState(0);
  const [pageSize, setPageSize] = hrmwUseState(100);

  /* Scoped to the signed-in operator, which is the whole point of this screen:
     it is NOT the network approval queue (that is Withdraws, /withdrawrequests,
     over the same table). `me` resolves through current_app_user(), so the
     filter is the operator's own id and not one supplied by the page. */
  const meFeed = useHrsFetch(() => window.sb.me(), []);
  const myId = meFeed.data && meFeed.data.id;
  const feed = useHrsFetch(
    () => (myId ? window.sb.list("withdrawalRequests", { limit: 200, filters: { user: myId } })
                : Promise.resolve({ ok: true, data: [] })),
    [myId]);
  const rows = hrmwUseMemo(() => (feed.data || []).map(hrmwFromRow), [feed.data]);

  const sorted = [...rows].sort((a, b) => {
    const get = HRMW_SORTERS[sort.key] || HRMW_SORTERS.addedTime;
    const d = get(a) - get(b);
    return sort.dir === "asc" ? d : -d;
  });
  const view = sorted.slice(page * pageSize, (page + 1) * pageSize);

  return (
    <HrsShell
      title="My withdrawal requests"
      subtitle="Withdrawal requests raised by this backoffice account — your own money leaving the platform, not the players'."
      gate={<>
        No <code>checkUserBoPerm</code> gate on this entry — visibility is purely role-based: the sidebar item is hidden
        for Skin Admin, Administration, Customer Care and Affiliate accounts and for levels ≥ Cashier(20), and the
        Report ▾ dropdown itself additionally requires <code>support_report</code> for Customer Care. Net visibility:
        Super Admin(0), Agent(8), Regulator(9), Promoter(10), Shop(15).{" "}
      </>}
      gateNote={<>
        Sidebar-only gate: none of the controller methods re-check roles, so e.g. a Skin Admin can still open{" "}
        <code>/withdraw/myrequests</code> by URL on the real platform.
      </>}
      explainer={{
        bullets: [
          <>Operator-as-requester: every row is hard-scoped to <b>your own account</b> (<code>withdrawal_requests.userid = Auth::user()-&gt;id</code>). This is <b>not</b> the network approval queue — that is <b>Withdraws</b> (<code>/withdrawrequests</code>), which processes everyone's requests from the same table.</>,
          <>Creating a request happens on a separate flow: <code>GET /withdraw/</code> lists the skin's enabled methods (<code>skin_withdraw_methods.bo_status = 1</code>) → <code>/withdraw/&#123;method&#125;</code> form (bank / pix / crypto) → <code>POST /withdraw/doWithdraw</code>. Your balance is <b>debited immediately</b> on submission; the request then waits Pending in the approval queue.</>,
          <>The real sidebar has <b>no link</b> to <code>/withdraw/</code> — the creation flow is reachable only by typing the URL. (UNCLEAR in the reference whether operators are expected to navigate there by hand; represented as this note rather than an invented button.)</>,
          <>No filters, no export, no row actions exist on the real screen — the 8-hour cancel button lives only on the player-frontend twin of this page. Canceled requests still count against the daily withdrawal limit (only Rejected is excluded).</>,
        ],
      }}
    >
      {/* No HrsKpis / HrsBars: the real controller initializes $totalBank/$totalPix and never uses them. */}
      {/* No HrsFilters: the real blade renders zero filter inputs (dead JS hooks only) — see header. */}
      {/* No HrsExport: no export exists on the real screen — see header. */}
      <HrsTable
        columns={HRMW_COLUMNS}
        rows={view}
        sort={sort}
        onSort={(next) => { setSort(next); setPage(0); }}
        rowKey="id"
        empty="No data available in table" /* DataTables' own empty string — shown when the operator has never raised a request */
        renderCard={(r) => <>
          <div className="hrs-card__top">
            <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
              <HrmwChip s={r.status} /><b>{hrsMoney(r.amount, r.currency)}</b>
            </span>
            <span>{hrmwDT(r.addedTime)}</span>
          </div>
          <div className="hrs-card__grid">
            <span>Result date</span><b>{r.chasingTime ? hrmwDT(r.chasingTime) : "—"}</b>
            <span>Method</span><b>{r.method}</b>
            <span>Description</span><b>{hrmwDescription(r) || "—"}</b>
            <span>Request data</span><b>{hrmwReqData(r) || "—"}</b>
          </div>
        </>}
      />
      <HrsPager
        page={page}
        pageSize={pageSize}
        total={rows.length}
        onPage={setPage}
        onPageSize={(n) => { setPageSize(n); setPage(0); }}
        sizes={[5, 10, 25, 50, 100]}
      />
    </HrsShell>
  );
};

/* Explicit global — overrides the legacy HostReports.jsx stub (load order). */
window.WithdrawalRequests = WithdrawalRequests;
