/**
 * Real X.509 leaf issuance (INV14). After the shared `assertLeafGate` passes, emit an X.509 v3
 * Ed25519 leaf whose subject key is the enrolled agent pubkey and whose only SAN is the host's
 * SPIFFE-ID URI — signed by the intermediate Ed25519 key. This is what `relay-auth`'s
 * `verifyAgentCert` accepts (it walks leaf → intermediate → self-signed root and parses the
 * `URI:spiffe://relay.<domain>/account/<a>/host/<h>` SAN).
 *
 * The SPIFFE-ID is built with relay-auth's OWN builder (`spiffeIdFor`, deep-imported) so the emitted
 * SAN can never drift from the verifier's parser. The intermediate PRIVATE key is a WebCrypto
 * `CryptoKey` imported non-extractable (never serialised back out — INV9).
 *
 * `reflect-metadata` must load before `@peculiar/x509` (tsyringe polyfill) — keep it first.
 */
import 'reflect-metadata'
import * as x509 from '@peculiar/x509'
import { webcrypto, randomBytes } from 'node:crypto'
import { spiffeIdFor } from 'relay-auth/src/agent/spiffe.js'
import type { HostStore } from '../store/ports.js'
import { assertLeafGate, DEFAULT_LEAF_TTL_SEC, type LeafSigner } from './sign.js'

x509.cryptoProvider.set(webcrypto)

/** Backdate notBefore slightly to tolerate small clock skew between control-plane and relay. */
const CLOCK_SKEW_SEC = 60

export interface RealLeafSignerDeps {
  readonly hosts: HostStore
  /** Intermediate Ed25519 PRIVATE signing key (WebCrypto, non-extractable). */
  readonly intermediateKey: CryptoKey
  /** Intermediate subject as a Name — used verbatim as the leaf issuer so `checkIssued` matches. */
  readonly issuerName: x509.Name
  /** DER of [intermediate, root] returned to the agent as its CA bundle (INV14). */
  readonly caChainDer: readonly Uint8Array[]
  /** Bare trust domain; the SPIFFE builder prepends `relay.`. */
  readonly trustDomain: string
  readonly leafTtlSec?: number
}

/** Import a raw 32-byte Ed25519 public key as a verifying WebCrypto CryptoKey (via SPKI DER). */
async function importEd25519Public(raw: Uint8Array): Promise<CryptoKey> {
  const prefix = Uint8Array.from([
    0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00,
  ])
  const spki = new Uint8Array(prefix.length + raw.length)
  spki.set(prefix, 0)
  spki.set(raw, prefix.length)
  return webcrypto.subtle.importKey('spki', spki, { name: 'Ed25519' }, true, ['verify'])
}

/**
 * Build the production leaf signer. Every issued leaf: X.509 v3, Ed25519 subject = agentPubkey,
 * URI SAN = the host's SPIFFE-ID, CA:false, KeyUsage digitalSignature, EKU clientAuth, validity
 * [now-skew, now+ttl]. Returns leaf DER + the injected CA chain DER; `redeem.ts` PEM-wraps both.
 */
export function createRealLeafSigner(deps: RealLeafSignerDeps): LeafSigner {
  const ttl = deps.leafTtlSec ?? DEFAULT_LEAF_TTL_SEC
  return {
    async signHostLeaf(hostId, agentPubkey, csr) {
      const host = await assertLeafGate(deps.hosts, hostId, agentPubkey, csr)
      const spiffe = spiffeIdFor(host.accountId, host.hostId, deps.trustDomain)
      const subjectKey = await importEd25519Public(agentPubkey)
      const now = Date.now()
      const leaf = await x509.X509CertificateGenerator.create({
        serialNumber: randomBytes(16).toString('hex'),
        subject: `CN=${host.hostId}`,
        issuer: deps.issuerName,
        notBefore: new Date(now - CLOCK_SKEW_SEC * 1000),
        notAfter: new Date(now + ttl * 1000),
        publicKey: subjectKey,
        signingKey: deps.intermediateKey,
        signingAlgorithm: { name: 'Ed25519' },
        extensions: [
          new x509.SubjectAlternativeNameExtension([{ type: 'url', value: spiffe }]),
          new x509.BasicConstraintsExtension(false, undefined, true),
          new x509.KeyUsagesExtension(x509.KeyUsageFlags.digitalSignature, true),
          new x509.ExtendedKeyUsageExtension([x509.ExtendedKeyUsage.clientAuth]),
        ],
      })
      return { cert: new Uint8Array(leaf.rawData), caChain: deps.caChainDer }
    },
  }
}

export interface LoadRealLeafSignerInput {
  readonly hosts: HostStore
  /** Intermediate Ed25519 private key, PKCS#8 PEM. */
  readonly intermediateKeyPem: string
  /** Intermediate certificate, PEM (single block). */
  readonly intermediateCertPem: string
  /** Self-signed root certificate, PEM (single block). */
  readonly rootCertPem: string
  readonly trustDomain: string
  readonly leafTtlSec?: number
}

function pemToDer(pem: string): ArrayBuffer {
  const body = pem.replace(/-----BEGIN [^-]+-----/g, '').replace(/-----END [^-]+-----/g, '').replace(/\s+/g, '')
  const bytes = Buffer.from(body, 'base64')
  return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer
}

/**
 * Construct a real leaf signer from PEM material (boot path). Imports the intermediate private key
 * (non-extractable — never re-serialised, INV9) and derives the issuer Name + CA chain DER from the
 * certs. THROWS on unreadable/malformed material so the control-plane fails fast at boot.
 */
export async function loadRealLeafSigner(input: LoadRealLeafSignerInput): Promise<LeafSigner> {
  const intermediateKey = await webcrypto.subtle.importKey(
    'pkcs8',
    pemToDer(input.intermediateKeyPem),
    { name: 'Ed25519' },
    false, // non-extractable: the raw private key can never leave the process (INV9)
    ['sign'],
  )
  const intermediateCert = new x509.X509Certificate(input.intermediateCertPem)
  const rootCert = new x509.X509Certificate(input.rootCertPem)
  return createRealLeafSigner({
    hosts: input.hosts,
    intermediateKey,
    issuerName: intermediateCert.subjectName,
    caChainDer: [new Uint8Array(intermediateCert.rawData), new Uint8Array(rootCert.rawData)],
    trustDomain: input.trustDomain,
    ...(input.leafTtlSec !== undefined ? { leafTtlSec: input.leafTtlSec } : {}),
  })
}
