/**
 * T3 — account registry (immutable, INV8). `createAccount` writes a version-1 snapshot;
 * `setAccountStatus` performs the atomic append-version + pointer-swap (prior snapshot stays
 * readable from `versions()`). Never mutates a lifecycle field in place.
 */
import type { AccountRecord, AccountStatus } from '../model/records.js'
import type { AccountStore } from '../store/ports.js'
import type { AuditWriter } from '../audit/log.js'
import { noopAuditWriter } from '../audit/log.js'
import type { PlanTier } from 'relay-contracts'
import { newUuid, nowIso } from '../util/ids.js'

export interface AccountRegistry {
  createAccount(plan: PlanTier): Promise<AccountRecord>
  getAccount(accountId: string): Promise<AccountRecord | null>
  setAccountStatus(accountId: string, status: AccountStatus): Promise<AccountRecord>
}

export interface AccountRegistryDeps {
  readonly accounts: AccountStore
  readonly audit?: AuditWriter
  readonly actor?: string
}

export function createAccountRegistry(deps: AccountRegistryDeps): AccountRegistry {
  const audit = deps.audit ?? noopAuditWriter()
  const actor = deps.actor ?? 'system'
  return {
    async createAccount(plan) {
      const rec: AccountRecord = {
        accountId: newUuid(), // unguessable, never recycled (INV1 precondition)
        plan,
        createdAt: nowIso(),
        status: 'active',
      }
      await deps.accounts.insert(rec)
      await audit.writeAuditEvent({
        action: 'account.create',
        principalId: actor,
        accountId: rec.accountId,
        hostId: null,
        ts: rec.createdAt,
        meta: { plan },
      })
      return rec
    },
    async getAccount(accountId) {
      return deps.accounts.get(accountId)
    },
    async setAccountStatus(accountId, status) {
      const next = await deps.accounts.swapStatus(accountId, status, actor) // NEW snapshot, atomic swap
      await audit.writeAuditEvent({
        action: status === 'suspended' ? 'account.suspend' : 'manage',
        principalId: actor,
        accountId,
        hostId: null,
        ts: nowIso(),
        meta: { status },
      })
      return next
    },
  }
}
