import { generateKeyPairSync, sign } from "node:crypto";
import { randomUUID } from "node:crypto";
import { RECEIPT_TTL_MS } from "../runtime/timing.js";
import { RUN_INTENT_BRIDGE_RECEIPT_CONTRACT_VERSION, RUN_INTENT_RECEIPT_SIGNATURE_PREFIX, runIntentBridgeReceiptSigningPayload, } from "./runIntentReceipts.js";
/**
 * Local dev-trust run-intent receipt signer.
 *
 * Local-first allows a run to start without the hosted backend by minting a
 * receipt the bridge itself trusts. This is intentionally limited:
 *
 *  - It is ONLY constructed in development/test mode whose trust comes from the
 *    development fixture (no operator-configured trusted keys). In production,
 *    or when real trusted keys are configured, `createLocalRunIntentReceiptSigner`
 *    returns `null` and no local minting is possible — the hosted-signed receipt
 *    path remains the only way to start a run.
 *  - The ephemeral private key never leaves this object. Callers receive only
 *    the public key (to register as trusted) and signed receipts.
 */
export const LOCAL_DEV_TRUST_KEY_ID = "pt-local-dev-trust";
const RECEIPT_STATUS_CREATED = "created";
const RECEIPT_NEXT_STEP_CODE = "start-local-bridge-run";
const RECEIPT_REASON_CODE = "local-bridge-required";
/**
 * Returns a signer only when local dev-trust minting is permitted, otherwise
 * `null`. Fail-closed: production mode and operator-configured trusted keys
 * both disable local minting.
 */
export function createLocalRunIntentReceiptSigner(config) {
    if (config.mode === "production") {
        return null;
    }
    const trust = config.runIntentReceiptTrust;
    const allDevelopmentFixture = trust.trustedPublicKeys.length > 0 &&
        trust.trustedPublicKeys.every((key) => key.source === "development-fixture");
    if (!allDevelopmentFixture) {
        // Operator configured real trusted keys — do not allow self-minting.
        return null;
    }
    const { publicKey, privateKey } = generateKeyPairSync("ec", {
        namedCurve: "P-256",
    });
    const trustedPublicKey = {
        keyId: LOCAL_DEV_TRUST_KEY_ID,
        publicKey,
        source: "development-fixture",
    };
    return new DefaultLocalRunIntentReceiptSigner(trustedPublicKey, privateKey, trust.issuer, trust.audience);
}
class DefaultLocalRunIntentReceiptSigner {
    trustedPublicKey;
    privateKey;
    issuer;
    audience;
    keyId;
    constructor(trustedPublicKey, privateKey, issuer, audience) {
        this.trustedPublicKey = trustedPublicKey;
        this.privateKey = privateKey;
        this.issuer = issuer;
        this.audience = audience;
        this.keyId = trustedPublicKey.keyId;
    }
    getTrustedPublicKey() {
        return this.trustedPublicKey;
    }
    mintReceipt(input) {
        const now = input.now ?? new Date();
        const issuedAt = now.toISOString();
        const expiresAt = new Date(now.getTime() + RECEIPT_TTL_MS).toISOString();
        const unsigned = {
            contractVersion: RUN_INTENT_BRIDGE_RECEIPT_CONTRACT_VERSION,
            receiptId: `rcpt_local_${randomUUID()}`,
            keyId: this.keyId,
            issuer: this.issuer,
            audience: this.audience,
            intentId: input.intentId ?? `intent_local_${randomUUID()}`,
            workspaceId: input.workspaceId,
            workItemId: input.workItemId,
            status: RECEIPT_STATUS_CREATED,
            nextStepCode: RECEIPT_NEXT_STEP_CODE,
            reasonCode: RECEIPT_REASON_CODE,
            issuedAt,
            expiresAt,
            signature: "",
        };
        const signatureBytes = sign("sha256", Buffer.from(runIntentBridgeReceiptSigningPayload(unsigned), "utf8"), { key: this.privateKey, dsaEncoding: "ieee-p1363" });
        return {
            ...unsigned,
            signature: RUN_INTENT_RECEIPT_SIGNATURE_PREFIX +
                signatureBytes.toString("base64url"),
        };
    }
}
