/**
 * §4.2 Account / host data model — Zod schemas + inferred TS types.
 * Postgres = ownership source of truth; Redis = live location (RouteEntry).
 * Records are immutable (INV8): updates insert a new row / swap a snapshot.
 */
import { z } from 'zod'

/** account.status (string-literal union, §4.2). */
export type AccountStatus = 'active' | 'suspended'
/** account.plan tier (string-literal union, §4.2). */
export type PlanTier = 'free' | 'personal' | 'pro' | 'team'
/** host.status (string-literal union, §4.2). */
export type HostStatus = 'online' | 'offline' | 'draining' | 'revoked'

export const AccountStatusSchema = z.enum(['active', 'suspended'])
export const PlanTierSchema = z.enum(['free', 'personal', 'pro', 'team'])
export const HostStatusSchema = z.enum(['online', 'offline', 'draining', 'revoked'])

/** ISO-8601 timestamptz as a string (control-plane serialization boundary). */
const IsoTimestamp = z.string().datetime({ offset: true })
/** Unguessable UUID identifiers (INV1: host_id never recycled). */
const Uuid = z.string().uuid()

/** accounts row (§4.2). */
export const AccountRecordSchema = z
  .object({
    accountId: Uuid,
    plan: PlanTierSchema,
    createdAt: IsoTimestamp,
    status: AccountStatusSchema,
  })
  .strict()
  .readonly()
export type AccountRecord = z.infer<typeof AccountRecordSchema>

/**
 * hosts row (§4.2). `agentPubkey` is the Ed25519 PUBLIC key only (INV4); the private
 * key never leaves the host. `enrollFpr` is pinned by the browser for E2E TOFU (§4.4).
 */
export const HostRecordSchema = z
  .object({
    hostId: Uuid,
    accountId: Uuid,
    subdomain: z.string().min(1),
    agentPubkey: z.instanceof(Uint8Array),
    enrollFpr: z.string().min(1),
    status: HostStatusSchema,
    lastSeen: IsoTimestamp,
    createdAt: IsoTimestamp,
    revokedAt: IsoTimestamp.nullable(),
  })
  .strict()
  .readonly()
export type HostRecord = z.infer<typeof HostRecordSchema>

/** sessions row (§4.2). `accountId` is DENORMALIZED for O(1) deny-by-default authz (INV3/INV6). */
export const SessionRecordSchema = z
  .object({
    sessionId: Uuid,
    hostId: Uuid,
    accountId: Uuid,
    createdAt: IsoTimestamp,
    lastAttachAt: IsoTimestamp,
  })
  .strict()
  .readonly()
export type SessionRecord = z.infer<typeof SessionRecordSchema>

/** Redis `route:{host_id}` value — live routing table, NOT source of truth (INV7). */
export const RouteEntrySchema = z
  .object({
    relayNodeId: z.string().min(1),
    updatedAt: IsoTimestamp,
  })
  .strict()
  .readonly()
export type RouteEntry = z.infer<typeof RouteEntrySchema>
