/**
 * §4.5 Pairing / enrollment shapes. P3 issues pairing codes and returns EnrollResult at BIND;
 * P2 redeems. `hostContentSecret` (FIX 3) is wrapped to the agent's enrolled Ed25519 identity
 * by P3 and unwrapped locally by P2 (private key never leaves the host, INV4).
 */
import { z } from 'zod'

/**
 * Result of a successful `POST /enroll` (§4.5). `hostContentSecret` is the wrapped-to-agent
 * input to §4.4 `deriveContentKey`; NEVER logged, NEVER sent to the relay.
 */
export interface EnrollResult {
  readonly hostId: string
  readonly subdomain: string
  readonly cert: string
  readonly caChain: string
  readonly hostContentSecret: Uint8Array // FIX 3 — wrapped to agent_pubkey by P3 at BIND
}

export const EnrollResultSchema = z
  .object({
    hostId: z.string().uuid(),
    subdomain: z.string().min(1),
    cert: z.string().min(1),
    caChain: z.string().min(1),
    hostContentSecret: z.instanceof(Uint8Array),
  })
  .strict()
  .readonly()

/**
 * pairing_codes row (§4.2/§4.5). Only the HASH of the single-use code is stored (INV5);
 * a non-null `redeemedAt` marks it spent (single-use, atomic compare-and-set at redeem).
 */
export interface PairingCodeRecord {
  readonly codeHash: string
  readonly accountId: string
  readonly expiresAt: string
  readonly redeemedAt: string | null
}

export const PairingCodeRecordSchema = z
  .object({
    codeHash: z.string().min(1),
    accountId: z.string().uuid(),
    expiresAt: z.string().datetime({ offset: true }),
    redeemedAt: z.string().datetime({ offset: true }).nullable(),
  })
  .strict()
  .readonly()
