/**
 * OBJECTIVE ORACLE (INV4/INV14) — proves the control-plane's REAL leaf issuer emits an X.509 leaf
 * that relay-auth's `verifyAgentCert` accepts, WITHOUT deploying either service.
 *
 * A throwaway Ed25519 root→intermediate chain is generated in-test; a leaf is issued through
 * `createRealLeafSigner` for a random account/host + agent pubkey; then relay-auth verifies the
 * leaf against the intermediate+root bundle with a fake host registry. Positive path asserts
 * `{ ok: true, hostId, accountId }`; negatives assert the exact reject reasons.
 */
import 'reflect-metadata'
import { describe, test, expect } from 'vitest'
import * as x509 from '@peculiar/x509'
import { webcrypto, randomUUID } from 'node:crypto'
import { verifyAgentCert, defaultParseX509 } from 'relay-auth/src/agent/verify-mtls.js'
import { spiffeIdFor } from 'relay-auth/src/agent/spiffe.js'
import type { HostRecord } from 'relay-contracts'
import { createMemoryStores } from '../src/store/memory.js'
import { createHostRegistry } from '../src/registry/hosts.js'
import { createRealLeafSigner, loadRealLeafSigner } from '../src/ca/issue.js'
import { buildCsr } from '../src/ca/csr.js'
import { fingerprint } from '../src/ca/fingerprint.js'
import { generateEd25519 } from '../src/util/crypto.js'

x509.cryptoProvider.set(webcrypto)

const TRUST_DOMAIN = 'example.com'
const DAY_MS = 24 * 60 * 60 * 1000

interface Ca {
  readonly intKey: CryptoKey
  readonly issuerName: x509.Name
  readonly caChainDer: readonly Uint8Array[]
  readonly caChainPem: string
  readonly intermediateKeyPem: string
  readonly intermediateCertPem: string
  readonly rootCertPem: string
}

type KeyPair = { readonly publicKey: CryptoKey; readonly privateKey: CryptoKey }

function derToPemLabeled(der: Uint8Array, label: string): string {
  const b64 = Buffer.from(der).toString('base64').match(/.{1,64}/g)?.join('\n') ?? ''
  return `-----BEGIN ${label}-----\n${b64}\n-----END ${label}-----\n`
}

async function makeCa(): Promise<Ca> {
  const subtle = webcrypto.subtle
  const rootKeys = (await subtle.generateKey({ name: 'Ed25519' }, true, ['sign', 'verify'])) as unknown as KeyPair
  const intKeys = (await subtle.generateKey({ name: 'Ed25519' }, true, ['sign', 'verify'])) as unknown as KeyPair
  const now = Date.now()
  const rootCert = await x509.X509CertificateGenerator.createSelfSigned({
    serialNumber: '01',
    name: 'CN=relay-root',
    notBefore: new Date(now - DAY_MS),
    notAfter: new Date(now + DAY_MS),
    keys: rootKeys,
    signingAlgorithm: { name: 'Ed25519' },
    extensions: [new x509.BasicConstraintsExtension(true, undefined, true)],
  })
  const intCert = await x509.X509CertificateGenerator.create({
    serialNumber: '02',
    subject: 'CN=relay-intermediate',
    issuer: rootCert.subjectName,
    notBefore: new Date(now - DAY_MS),
    notAfter: new Date(now + DAY_MS),
    publicKey: intKeys.publicKey,
    signingKey: rootKeys.privateKey,
    signingAlgorithm: { name: 'Ed25519' },
    extensions: [new x509.BasicConstraintsExtension(true, undefined, true)],
  })
  const intKeyPkcs8 = new Uint8Array(await subtle.exportKey('pkcs8', intKeys.privateKey))
  return {
    intKey: intKeys.privateKey,
    issuerName: intCert.subjectName,
    caChainDer: [new Uint8Array(intCert.rawData), new Uint8Array(rootCert.rawData)],
    caChainPem: `${intCert.toString('pem')}\n${rootCert.toString('pem')}`,
    intermediateKeyPem: derToPemLabeled(intKeyPkcs8, 'PRIVATE KEY'),
    intermediateCertPem: intCert.toString('pem'),
    rootCertPem: rootCert.toString('pem'),
  }
}

function derToPem(der: Uint8Array): string {
  return new x509.X509Certificate(der).toString('pem')
}

/** Minimal relay-contracts HostRecord for the fake registry (only accountId/status are read). */
function fakeHost(hostId: string, accountId: string, status: HostRecord['status']): HostRecord {
  return {
    hostId,
    accountId,
    subdomain: 'host',
    agentPubkey: new Uint8Array(32),
    enrollFpr: 'fpr',
    status,
    lastSeen: new Date().toISOString(),
    createdAt: new Date().toISOString(),
    revokedAt: status === 'revoked' ? new Date().toISOString() : null,
  } as HostRecord
}

async function issueLeaf() {
  const ca = await makeCa()
  const stores = createMemoryStores()
  const hosts = createHostRegistry({ hosts: stores.hosts })
  const accountId = randomUUID()
  const { publicKeyRaw, privateKey } = generateEd25519()
  const host = await hosts.bindHost({
    accountId,
    subdomain: 'alice',
    agentPubkey: publicKeyRaw,
    enrollFpr: fingerprint(publicKeyRaw),
  })
  const signer = createRealLeafSigner({
    hosts: stores.hosts,
    intermediateKey: ca.intKey,
    issuerName: ca.issuerName,
    caChainDer: ca.caChainDer,
    trustDomain: TRUST_DOMAIN,
  })
  const { cert, caChain } = await signer.signHostLeaf(host.hostId, publicKeyRaw, buildCsr(privateKey, publicKeyRaw))
  return { ca, accountId, hostId: host.hostId, publicKeyRaw, leafPem: derToPem(cert), caChain }
}

describe('interop: control-plane real leaf ⇄ relay-auth verifyAgentCert', () => {
  test('valid leaf for an active enrolled host → { ok: true, hostId, accountId }', async () => {
    const { ca, accountId, hostId, leafPem, caChain } = await issueLeaf()
    expect(caChain).toHaveLength(2) // intermediate + root DER
    const registry = { getById: async (id: string) => (id === hostId ? fakeHost(hostId, accountId, 'online') : null) }
    const res = await verifyAgentCert(leafPem, ca.caChainPem, Math.floor(Date.now() / 1000), registry, defaultParseX509)
    expect(res).toEqual({ ok: true, hostId, accountId })
  })

  test('SPIFFE accountId ≠ registry accountId → spiffe_account_mismatch', async () => {
    const { ca, hostId, leafPem } = await issueLeaf()
    const registry = { getById: async (id: string) => (id === hostId ? fakeHost(hostId, randomUUID(), 'online') : null) }
    const res = await verifyAgentCert(leafPem, ca.caChainPem, Math.floor(Date.now() / 1000), registry, defaultParseX509)
    expect(res.ok).toBe(false)
    expect(res.reason).toBe('spiffe_account_mismatch')
  })

  test('revoked host → host_revoked', async () => {
    const { ca, accountId, hostId, leafPem } = await issueLeaf()
    const registry = { getById: async (id: string) => (id === hostId ? fakeHost(hostId, accountId, 'revoked') : null) }
    const res = await verifyAgentCert(leafPem, ca.caChainPem, Math.floor(Date.now() / 1000), registry, defaultParseX509)
    expect(res.ok).toBe(false)
    expect(res.reason).toBe('host_revoked')
  })

  test('expired leaf → expired', async () => {
    const ca = await makeCa()
    const accountId = randomUUID()
    const hostId = randomUUID()
    const { publicKeyRaw } = generateEd25519()
    const spiffe = spiffeIdFor(accountId, hostId, TRUST_DOMAIN)
    const prefix = Uint8Array.from([0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00])
    const spki = new Uint8Array(44)
    spki.set(prefix, 0)
    spki.set(publicKeyRaw, 12)
    const subjectKey = await webcrypto.subtle.importKey('spki', spki, { name: 'Ed25519' }, true, ['verify'])
    const now = Date.now()
    const expiredLeaf = await x509.X509CertificateGenerator.create({
      serialNumber: '0e',
      subject: `CN=${hostId}`,
      issuer: ca.issuerName,
      notBefore: new Date(now - 2 * DAY_MS),
      notAfter: new Date(now - DAY_MS), // already expired
      publicKey: subjectKey,
      signingKey: ca.intKey,
      signingAlgorithm: { name: 'Ed25519' },
      extensions: [new x509.SubjectAlternativeNameExtension([{ type: 'url', value: spiffe }])],
    })
    const registry = { getById: async (id: string) => (id === hostId ? fakeHost(hostId, accountId, 'online') : null) }
    const res = await verifyAgentCert(
      expiredLeaf.toString('pem'),
      ca.caChainPem,
      Math.floor(Date.now() / 1000),
      registry,
      defaultParseX509,
    )
    expect(res.ok).toBe(false)
    expect(res.reason).toBe('expired')
  })

  test('boot path: loadRealLeafSigner (PEM material) issues a verifiable leaf', async () => {
    const ca = await makeCa()
    const stores = createMemoryStores()
    const hosts = createHostRegistry({ hosts: stores.hosts })
    const accountId = randomUUID()
    const { publicKeyRaw, privateKey } = generateEd25519()
    const host = await hosts.bindHost({
      accountId,
      subdomain: 'boot',
      agentPubkey: publicKeyRaw,
      enrollFpr: fingerprint(publicKeyRaw),
    })
    const signer = await loadRealLeafSigner({
      hosts: stores.hosts,
      intermediateKeyPem: ca.intermediateKeyPem,
      intermediateCertPem: ca.intermediateCertPem,
      rootCertPem: ca.rootCertPem,
      trustDomain: TRUST_DOMAIN,
    })
    const { cert } = await signer.signHostLeaf(host.hostId, publicKeyRaw, buildCsr(privateKey, publicKeyRaw))
    const registry = {
      getById: async (id: string) => (id === host.hostId ? fakeHost(host.hostId, accountId, 'online') : null),
    }
    const res = await verifyAgentCert(derToPem(cert), ca.caChainPem, Math.floor(Date.now() / 1000), registry, defaultParseX509)
    expect(res).toEqual({ ok: true, hostId: host.hostId, accountId })
  })

  test('intermediate-only bundle (no root) → chain_invalid', async () => {
    const { ca, accountId, hostId, leafPem } = await issueLeaf()
    const intermediateOnly = ca.caChainPem.split('-----END CERTIFICATE-----')[0]! + '-----END CERTIFICATE-----\n'
    const registry = { getById: async (id: string) => (id === hostId ? fakeHost(hostId, accountId, 'online') : null) }
    const res = await verifyAgentCert(leafPem, intermediateOnly, Math.floor(Date.now() / 1000), registry, defaultParseX509)
    expect(res.ok).toBe(false)
    expect(res.reason).toBe('chain_invalid')
  })
})
