import { describe, expect, it } from 'vitest'
import {
  AccountRecordSchema,
  HostRecordSchema,
  KillSignalSchema,
  RELAY_REVOCATIONS_CHANNEL,
  REVOCATION_PUSH_BUDGET_MS,
  RevocationScopeSchema,
  RouteEntrySchema,
  SessionRecordSchema,
  INV8_VERSION_TABLE_DDL,
  HOST_VERSIONS_DDL,
  HOSTS_CURRENT_DDL,
} from '../src/index.js'

const UUID = '11111111-1111-4111-8111-111111111111'
const TS = '2026-07-01T00:00:00.000Z'

describe('§4.2 account/host/session Zod schemas', () => {
  it('accepts a valid HostRecord', () => {
    const rec = {
      hostId: UUID,
      accountId: UUID,
      subdomain: 'alice',
      agentPubkey: new Uint8Array([1, 2, 3]),
      enrollFpr: 'fpr:abc',
      status: 'online',
      lastSeen: TS,
      createdAt: TS,
      revokedAt: null,
    }
    expect(HostRecordSchema.parse(rec)).toEqual(rec)
  })

  it('rejects a HostRecord with an invalid status', () => {
    expect(() =>
      HostRecordSchema.parse({
        hostId: UUID,
        accountId: UUID,
        subdomain: 'a',
        agentPubkey: new Uint8Array(),
        enrollFpr: 'f',
        status: 'zombie',
        lastSeen: TS,
        createdAt: TS,
        revokedAt: null,
      }),
    ).toThrow()
  })

  it('rejects a HostRecord with a non-UUID hostId', () => {
    const bad = {
      hostId: 'not-a-uuid',
      accountId: UUID,
      subdomain: 'a',
      agentPubkey: new Uint8Array(),
      enrollFpr: 'f',
      status: 'online',
      lastSeen: TS,
      createdAt: TS,
      revokedAt: null,
    }
    expect(HostRecordSchema.safeParse(bad).success).toBe(false)
  })

  it('rejects unknown extra keys (strict)', () => {
    expect(
      AccountRecordSchema.safeParse({
        accountId: UUID,
        plan: 'pro',
        createdAt: TS,
        status: 'active',
        extra: 1,
      }).success,
    ).toBe(false)
  })

  it('accepts a valid AccountRecord across all plan tiers', () => {
    for (const plan of ['free', 'personal', 'pro', 'team'] as const) {
      expect(AccountRecordSchema.parse({ accountId: UUID, plan, createdAt: TS, status: 'active' }).plan).toBe(
        plan,
      )
    }
  })

  it('validates SessionRecord and RouteEntry', () => {
    expect(
      SessionRecordSchema.parse({
        sessionId: UUID,
        hostId: UUID,
        accountId: UUID,
        createdAt: TS,
        lastAttachAt: TS,
      }).sessionId,
    ).toBe(UUID)
    expect(RouteEntrySchema.parse({ relayNodeId: 'node-1', updatedAt: TS }).relayNodeId).toBe('node-1')
  })
})

describe('§4.2 FIX 4 revocation teardown shapes', () => {
  it('exposes the frozen channel + budget constants', () => {
    expect(RELAY_REVOCATIONS_CHANNEL).toBe('relay:revocations')
    expect(REVOCATION_PUSH_BUDGET_MS).toBe(2000)
  })

  it('accepts each RevocationScope variant', () => {
    expect(RevocationScopeSchema.parse({ kind: 'host', hostId: UUID }).kind).toBe('host')
    expect(RevocationScopeSchema.parse({ kind: 'account', accountId: UUID }).kind).toBe('account')
    expect(RevocationScopeSchema.parse({ kind: 'global' }).kind).toBe('global')
  })

  it('rejects a host scope missing hostId', () => {
    expect(RevocationScopeSchema.safeParse({ kind: 'host' }).success).toBe(false)
  })

  it('validates a full KillSignal', () => {
    const signal = { scope: { kind: 'global' }, at: 1719800000, reason: 'operator drain' }
    expect(KillSignalSchema.parse(signal)).toEqual(signal)
  })
})

describe('§4.2 INV8 version-table DDL contract', () => {
  it('exposes host_versions + hosts_current DDL in order', () => {
    expect(INV8_VERSION_TABLE_DDL).toEqual([HOST_VERSIONS_DDL, HOSTS_CURRENT_DDL])
    expect(HOST_VERSIONS_DDL).toContain('host_versions')
    expect(HOST_VERSIONS_DDL).toContain('supersedes')
    expect(HOSTS_CURRENT_DDL).toContain('hosts_current')
    expect(HOSTS_CURRENT_DDL).toContain('version_id')
  })
})
