// ============================================================================
// DEL-VECTORS checker (Account Doors spec 7.2): recompute every doors vector
// from its pinned inputs and compare byte-exact against
// testing/conformance/doors-vectors.json. One flipped byte fails loudly.
// Ship this beside the vectors in the public conformance package so a
// self-hosting implementation can validate its own crypto:
//   npx tsx testing/conformance/check-doors-vectors.ts
// ============================================================================

import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { dirname, join } from 'node:path'
import sodium from 'libsodium-wrappers-sumo'
import { getProvider } from '../../src/sodium-provider.ts'
import { deriveKeys } from '../../shared/sovereign/keys.ts'
import { createGenesisEntry, countersignGenesis, createRotationEntry, didFromGenesis, verifyCountersig, validateRotationLog } from '../../shared/sovereign/rotation.ts'
import { toHex, fromHex } from '../../shared/sovereign/internal.ts'
import { CHILD_CUSTODY_LABEL, DEVICE_CUSTODY_LABEL } from '../../shared/sovereign/custody-labels.ts'

const FILE = join(dirname(fileURLToPath(import.meta.url)), 'doors-vectors.json')

export async function checkDoorsVectors(): Promise<string[]> {
    await sodium.ready
    const p = await getProvider()
    const vectors = JSON.parse(readFileSync(FILE, 'utf8'))
    const failures: string[] = []
    const expectEq = (name: string, got: string, want: string) => {
        if (got !== want) failures.push(`${name}: got ${got.slice(0, 32)}..., want ${want.slice(0, 32)}...`)
    }

    for (const v of vectors.password_wrap) {
        const kek = sodium.crypto_pwhash(
            sodium.crypto_secretbox_KEYBYTES, v.password, fromHex(v.blob.salt),
            v.blob.ops, v.blob.mem, sodium.crypto_pwhash_ALG_ARGON2ID13,
        )
        expectEq(`${v.name}: kek`, toHex(kek), v.kek)
        const wrapped = sodium.crypto_secretbox_easy(fromHex(v.seed), fromHex(v.blob.nonce), kek)
        expectEq(`${v.name}: wrapped`, toHex(wrapped), v.blob.wrapped)
        const opened = sodium.crypto_secretbox_open_easy(fromHex(v.blob.wrapped), fromHex(v.blob.nonce), kek)
        expectEq(`${v.name}: unwrap`, toHex(opened), v.seed)
    }

    for (const v of vectors.child_genesis_countersig) {
        const parentKeys = deriveKeys(p, fromHex(v.parent_seed))
        const childKeys = deriveKeys(p, fromHex(v.child_seed))
        const parentGenesis = createGenesisEntry(p, parentKeys.identity, parentKeys.sealing.publicKey, { custody: DEVICE_CUSTODY_LABEL })
        expectEq(`${v.name}: parent genesis`, JSON.stringify(parentGenesis), JSON.stringify(v.parent_genesis))
        const parentDid = didFromGenesis(p, parentGenesis)
        expectEq(`${v.name}: parent did`, parentDid, v.parent_did)
        let childGenesis = createGenesisEntry(p, childKeys.identity, childKeys.sealing.publicKey, {
            // IMPORTED from custody-labels.ts, the module the reference
            // implementation (keys.ts createChildIdentity) executes, never
            // typed here: a label drift now reddens this check against the
            // pinned vector file instead of agreeing with itself
            // (max-review fix, 2026-07-25).
            custody: CHILD_CUSTODY_LABEL, supervisor_did: parentDid,
        })
        childGenesis = countersignGenesis(p, childGenesis, parentDid, parentKeys.identity)
        expectEq(`${v.name}: child genesis + countersig`, JSON.stringify(childGenesis), JSON.stringify(v.child_genesis))
        expectEq(`${v.name}: child did`, didFromGenesis(p, childGenesis), v.child_did)
        if (!verifyCountersig(p, v.child_genesis)) failures.push(`${v.name}: stored countersignature does not verify`)
        try { validateRotationLog(p, [v.child_genesis]) } catch (e) { failures.push(`${v.name}: stored child log does not validate: ${e}`) }
    }
    for (const v of vectors.device_add ?? []) {
        const identityKeys = deriveKeys(p, fromHex(v.identity_seed))
        const genesis = createGenesisEntry(p, identityKeys.identity, identityKeys.sealing.publicKey, { custody: DEVICE_CUSTODY_LABEL })
        expectEq(`${v.name}: genesis`, JSON.stringify(genesis), JSON.stringify(v.genesis))
        expectEq(`${v.name}: did`, didFromGenesis(p, genesis), v.did)
        const devicePub = toHex(sodium.crypto_sign_seed_keypair(fromHex(v.device_seed)).publicKey)
        expectEq(`${v.name}: device pub`, devicePub, v.device_pub)
        const state = validateRotationLog(p, [genesis])
        const entry = createRotationEntry(p, state, 'rotation.device_add', { device_pub: devicePub, name: 'Conformance Device' }, identityKeys.identity)
        expectEq(`${v.name}: device_add entry`, JSON.stringify(entry), JSON.stringify(v.device_add))
        try { validateRotationLog(p, [v.genesis, v.device_add]) } catch (e) { failures.push(`${v.name}: stored log does not validate: ${e}`) }
    }
    return failures
}

// Direct invocation: report and exit.
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
    checkDoorsVectors().then(failures => {
        if (failures.length) {
            console.error('DOORS VECTORS FAIL:')
            for (const f of failures) console.error('  ' + f)
            process.exit(1)
        }
        console.log('Doors vectors byte-exact: password wrap, child genesis countersignature and device_add entry all reproduce.')
    }).catch(e => { console.error(e); process.exit(1) })
}
