import * as Atom from "effect/unstable/reactivity/Atom";

import { AdminApiClient } from "./admin-client";
import { ReactivityKey } from "./reactivity-keys";

// ---------------------------------------------------------------------------
// Admin atoms — the tenant-wide users view behind `/admin/users*`.
//
// Read-only by construction: the admin plane serves GETs only (the owner policy
// rejects writes at tenant reach), so there are no mutations here and every
// atom carries the same reactivity key.
//
// Paging and the search term are part of the atom identity, so each page of
// each search is its own cache entry and stepping back to a visited page is
// instant. `Atom.family` (not a bare arrow) because the page component
// re-derives the key object on every render — a fresh atom per render would
// refetch in a loop.
// ---------------------------------------------------------------------------

/** How many users one page of the list shows. Well inside the contract's
 *  1..500 bound; the joined endpoint reads per-user connections, so a modest
 *  page keeps that join cheap. */
export const ADMIN_USERS_PAGE_SIZE = 25;

export interface AdminUsersPage {
  readonly limit: number;
  readonly offset: number;
  /** The `?search=` term (name or email substring), already debounced by the
   *  page. `""` is no filter and is sent as no param at all, so the unfiltered
   *  list keeps one cache identity regardless of how the term was cleared. */
  readonly search: string;
}

/**
 * One page of users joined with their connections — what the list renders.
 *
 * Asks for one row MORE than the page size so the pager can tell "there is a
 * next page" from "this is the last one" without a count endpoint (the contract
 * returns no total). The page component drops the extra row.
 */
export const adminUsersWithConnectionsAtom = Atom.family((page: AdminUsersPage) =>
  AdminApiClient.query("adminUsers", "listUsersWithConnections", {
    query: {
      limit: page.limit + 1,
      offset: page.offset,
      ...(page.search === "" ? {} : { search: page.search }),
    },
    timeToLive: "30 seconds",
    reactivityKeys: [ReactivityKey.adminUsers],
  }),
);

/** One user's connections, for the detail pane. A separate read rather than a
 *  slice of the list so opening a user is correct even when the list page it
 *  came from has since gone stale. */
export const adminUserConnectionsAtom = Atom.family((externalId: string) =>
  AdminApiClient.query("adminUsers", "listUserConnections", {
    params: { externalId },
    timeToLive: "30 seconds",
    reactivityKeys: [ReactivityKey.adminUsers],
  }),
);
