import type { PageParams, Paginated } from '@/lib/api/types';

/**
 * Admin domain — the backoffice-owned data the f15 consoles read and act on: platform config, the
 * Iranian-holiday calendar, the append-only audit trail, the internal support-alert worklist, and RBAC
 * role grants. Shapes derive from the **b1** config/reference contract
 * (`dev/contracts/domains/config-reference.md`) and the **b15** admin contract
 * (`dev/contracts/domains/messaging-notifications-admin.md`); the wire is camelCase and `clientFetch`
 * unwraps the `ApiResult<T>` envelope, so these are the post-`unwrap()` payloads.
 *
 * Load-bearing rules (phase §5):
 *  - **Internal-only:** `SupportAlert`s are staff-only and must never reach a non-admin surface.
 *  - **Server is the authority:** config parsing is *rendering by `dataType`* only; the client validates at
 *    the boundary (a rate is 0–1) but never re-derives money, holiday shifts, or eligibility.
 *  - **Append-only audit:** there is no edit/delete — the viewer is read-only.
 *
 * Enums cross the wire as stable string codes, mirrored here as string-literal unions.
 */

// ── Config ────────────────────────────────────────────────────────────────────────────────────────────
/** `platform_configs.data_type` — how to parse (and which typed input to render for) a config `value`. */
export type ConfigDataType = 'string' | 'int' | 'decimal' | 'bool' | 'json';

/**
 * `PlatformConfigDto` (b1). `value` is the **raw string** — parse per `dataType`. `updatedAt`/`updatedBy`
 * are **not** on the b1 wire (REQ-029) — optional and mock-supplied until delivered; the row degrades
 * gracefully without them.
 */
export interface PlatformConfig {
  key: string;
  value: string;
  dataType: ConfigDataType;
  description: string | null;
  updatedAt?: string | null;
  updatedBy?: string | null;
}

/** `action` on an audit/config-change row. */
export type AuditAction = 'created' | 'updated' | 'deleted';

/**
 * A config change-history row, derived from `ConfigChangeDto` (b1). The wire carries `changedFieldsJson`
 * (`{ "Value": { "old": …, "new": … } }`); the client parses the value delta into `oldValue`/`newValue`
 * for the drawer so finance can prove the rate in effect at any past moment.
 */
export interface ConfigChange {
  id: number;
  action: AuditAction;
  actorUserId: number | null;
  occurredAt: string;
  oldValue: string | null;
  newValue: string | null;
}

// ── Holidays ──────────────────────────────────────────────────────────────────────────────────────────
/** `iranian_holidays.type`. */
export type HolidayType = 'official' | 'religious' | 'national';

/** `HolidayDto` (b1). `isBankClosed` is what shifts payout scheduling (server-computed). */
export interface Holiday {
  id: number;
  holidayDate: string;
  nameFa: string;
  type: HolidayType;
  isBankClosed: boolean;
}

/** Upsert body (`upsert_holiday`, keyed on `holidayDate`). */
export interface HolidayInput {
  holidayDate: string;
  nameFa: string;
  type: HolidayType;
  isBankClosed: boolean;
}

/** Holiday list range. */
export interface HolidayFilters {
  from?: string;
  to?: string;
}

// ── Audit ─────────────────────────────────────────────────────────────────────────────────────────────
/** `AuditLogDto` (b1). `changedFields` is the parsed `changedFieldsJson` (field → {old,new}); PII redacted. */
export interface AuditLogEntry {
  id: number;
  entityType: string;
  entityId: string;
  action: string;
  actorUserId: number | null;
  occurredAt: string;
  changedFields: Record<string, { old: unknown; new: unknown }> | null;
}

/**
 * Audit filters. The b1 wire supports only `entityType`/`entityId` (REQ-030 covers actor/action/date) —
 * the extra filters are honoured by the mock and requested from the backend; the real client passes the
 * supported ones and lets the rest degrade.
 */
export interface AuditFilters {
  entityType?: string;
  entityId?: string;
  actorUserId?: number;
  action?: string;
  from?: string;
  to?: string;
}

// ── Support alerts ────────────────────────────────────────────────────────────────────────────────────
/** `support_alert.type` — the broad b15 union (superset of the b1 list). */
export type SupportAlertType =
  | 'low_rating'
  | 'evv_no_show'
  | 'evv_location_mismatch'
  | 'verification_expired'
  | 'shared_sim'
  | 'payment_anomaly'
  | 'fraud_signal'
  | 'nurse_clawback'
  | 'emergency';

export type SupportAlertSeverity = 'low' | 'medium' | 'high';
export type SupportAlertStatus = 'open' | 'assigned' | 'resolved';

/** `SupportAlertDto` (b1/b15). **Internal-only** — never rendered outside an admin route. */
export interface SupportAlert {
  id: number;
  type: SupportAlertType;
  severity: SupportAlertSeverity;
  status: SupportAlertStatus;
  entityType: string;
  entityId: string;
  bookingId: number | null;
  reviewId: number | null;
  ownerUserId: number | null;
  resolutionNote: string | null;
  resolvedAt: string | null;
  createdAt: string;
}

export interface SupportAlertFilters {
  type?: SupportAlertType;
  status?: SupportAlertStatus;
  ownerUserId?: number;
}

// ── RBAC (b15 — role endpoints not yet in the contract; mock-primary, REQ-031) ─────────────────────────
/** The fine-grained admin roles the RBAC grid grants/revokes (aligned with the b2 `AdminRole` enum). */
export type AdminRole = 'super_admin' | 'admin' | 'support' | 'finance' | 'moderation';

/** A role grant row (`RoleGrant`). `revokedAt` set once revoked. */
export interface RoleGrant {
  userId: number;
  role: AdminRole;
  grantedBy: number | null;
  grantedAt: string;
  revokedAt: string | null;
}

// ── The seam ──────────────────────────────────────────────────────────────────────────────────────────
/**
 * The admin API seam — the real HTTP client and the in-memory mock both implement it; selection is by
 * config (`USE_ADMIN_MOCK`), never scattered `if (mock)` checks. Mutations return void (the wire returns
 * `true`); hooks invalidate the affected keys.
 */
export interface AdminApi {
  // config
  listConfigs(params: PageParams): Promise<Paginated<PlatformConfig>>;
  updateConfig(key: string, value: string): Promise<void>;
  getConfigHistory(key: string, params: PageParams): Promise<Paginated<ConfigChange>>;
  // holidays
  listHolidays(filters: HolidayFilters, params: PageParams): Promise<Paginated<Holiday>>;
  upsertHoliday(input: HolidayInput): Promise<void>;
  // audit
  listAuditLogs(filters: AuditFilters, params: PageParams): Promise<Paginated<AuditLogEntry>>;
  // support alerts
  listSupportAlerts(filters: SupportAlertFilters, params: PageParams): Promise<Paginated<SupportAlert>>;
  assignSupportAlert(alertId: number, ownerUserId: number): Promise<void>;
  resolveSupportAlert(alertId: number, note: string): Promise<void>;
  // rbac (deferred-if-missing)
  listRoles(userId?: number): Promise<RoleGrant[]>;
  grantRole(userId: number, role: AdminRole): Promise<void>;
  revokeRole(userId: number, role: AdminRole): Promise<void>;
}
