/**
 * T9 · SPIFFE-ID scheme for per-host / per-device agent identity (INV4/INV14).
 * Forms: `spiffe://relay.<domain>/account/<accountId>/host/<hostId>` (frp control channel) and
 * `.../account/<accountId>/device/<deviceId>` (device data path, FIX H-cp-2 / H-native-6).
 */
import type { SpiffeId } from '../types.js'
import { SpiffeIdSchema } from '../types.js'

/** Which identity arm a SPIFFE-ID names: a host agent or an end-user device. */
export type SpiffeKind = 'host' | 'device'

export class SpiffeError extends Error {
  constructor(message: string) {
    super(message)
    this.name = 'SpiffeError'
  }
}

/** Trust domain from env (INV9 config), defaulting to a safe placeholder for local/dev. */
export function trustDomain(env: NodeJS.ProcessEnv = process.env): string {
  const d = env.RELAY_TRUST_DOMAIN
  return d !== undefined && d.length > 0 ? d : 'example.com'
}

/**
 * Build a SPIFFE-ID. The optional 4th `kind` param defaults to `'host'`, so existing 3-arg
 * callers (e.g. control-plane `ca/issue.ts`) are UNCHANGED. Pass `'device'` for device leaves.
 */
export function spiffeIdFor(
  accountId: string,
  id: string,
  domain = trustDomain(),
  kind: SpiffeKind = 'host',
): SpiffeId {
  if (accountId.length === 0 || id.length === 0) {
    throw new SpiffeError('accountId and id are required')
  }
  const uri = `spiffe://relay.${domain}/account/${accountId}/${kind}/${id}`
  return SpiffeIdSchema.parse(uri)
}

const PARSE_RE =
  /^spiffe:\/\/relay\.[a-z0-9.-]+\/account\/([A-Za-z0-9_-]+)\/(host|device)\/([A-Za-z0-9_-]+)$/

export function parseSpiffeId(uri: SpiffeId): { accountId: string; id: string; kind: SpiffeKind } {
  const parsed = SpiffeIdSchema.safeParse(uri) // rejects path-traversal / wildcard / malformed
  if (!parsed.success) throw new SpiffeError('invalid SPIFFE-ID (malformed / traversal / wildcard)')
  const m = PARSE_RE.exec(uri)
  if (m === null) throw new SpiffeError('unparseable SPIFFE-ID')
  return { accountId: m[1]!, kind: m[2]! as SpiffeKind, id: m[3]! }
}
