/**
 * INTENT GATEWAY - Jurisdictional Router / Governance Topology Selector
 * @packageDocumentation
 */
import { createHash } from "node:crypto";
import { AiActClassifier } from "./ai-act-classifier.js";
import { JurisdictionResolver } from "./jurisdiction-resolver.js";
import { PolicyComposer } from "./policy-composer.js";
import { RegimeSelector } from "./regime-selector.js";
import { DEFAULT_GATEWAY_CONFIG } from "./types.js";
import { createLogger } from "../common/logger.js";
import { extractTenantId } from "../common/tenant-context.js";
const logger = createLogger({ component: "intent-gateway" });
export class GatewayConflictError extends Error {
    conflicts;
    constructor(conflicts) {
        super("Intent blocked by unresolved policy conflicts: " +
            conflicts.map((c) => c.description).join("; "));
        this.name = "GatewayConflictError";
        this.conflicts = conflicts;
    }
}
const EU_EEA_CODES = new Set(["EU"]);
export class IntentGateway {
    intentService;
    config;
    jurisdictionResolver;
    policyComposer;
    regimeSelector;
    aiActClassifier;
    cache = new Map();
    constructor(intentService, config) {
        this.intentService = intentService;
        this.config = { ...DEFAULT_GATEWAY_CONFIG, ...config };
        this.jurisdictionResolver = new JurisdictionResolver(this.config);
        this.policyComposer = new PolicyComposer();
        this.regimeSelector = new RegimeSelector();
        this.aiActClassifier = new AiActClassifier();
        logger.info({
            enabled: this.config.enabled,
            defaultJurisdiction: this.config.defaultJurisdiction,
        }, "IntentGateway initialized");
    }
    async dispatch(submission, options) {
        if (!this.config.enabled) {
            const intent = await this.intentService.submit(submission, options);
            return this.createPassthroughResult(intent);
        }
        try {
            const intentMeta = submission.context;
            const jCtx = this.jurisdictionResolver.resolve(options.ctx, intentMeta);
            const tenantId = extractTenantId(options.ctx);
            const tConfig = this.jurisdictionResolver.getTenantConfig(tenantId);
            const policySet = this.policyComposer.compose(jCtx, tConfig?.customPolicyBundles);
            const warnings = [];
            if (policySet.unresolvedConflicts.length > 0) {
                if (this.config.blockOnConflicts && !policySet.isValid)
                    throw new GatewayConflictError(policySet.unresolvedConflicts);
                for (const conflict of policySet.unresolvedConflicts)
                    warnings.push("Unresolved: " + conflict.description);
            }
            let aiAct;
            if (jCtx.primaryJurisdictions.some((j) => EU_EEA_CODES.has(j))) {
                const goal = typeof submission.goal === "string"
                    ? submission.goal
                    : "";
                const iType = typeof submission.intentType === "string"
                    ? submission.intentType
                    : undefined;
                aiAct = this.aiActClassifier.classify(goal, intentMeta, iType);
                if (aiAct.classification === "unacceptable")
                    warnings.push("EU AI Act: PROHIBITED - " + aiAct.reasoning);
            }
            const regime = this.regimeSelector.select(jCtx, policySet);
            if (aiAct) {
                regime.aiActClassification = aiAct.classification;
                regime.aiActHighRiskCategory = aiAct.highRiskCategory;
            }
            this.cacheRegime(tenantId, jCtx, regime, policySet);
            const enriched = {
                ...options,
                trustSnapshot: {
                    ...(options.trustSnapshot ?? {}),
                    __governanceRegime: {
                        regimeId: regime.regimeId,
                        name: regime.name,
                        jurisdictions: regime.jurisdictions,
                        cryptoSuite: regime.cryptoSuite,
                        minimumTrustLevel: regime.minimumTrustLevel,
                        aiActClassification: regime.aiActClassification,
                        conformityAssessmentRequired: regime.conformityAssessmentRequired,
                    },
                },
            };
            if (!enriched.trustLevel ||
                enriched.trustLevel < regime.minimumTrustLevel)
                enriched.trustLevel = regime.minimumTrustLevel;
            if (this.config.logRegimeDecisions)
                logger.info({
                    regimeId: regime.regimeId,
                    name: regime.name,
                    tenantId,
                    cryptoSuite: regime.cryptoSuite,
                    minimumTrustLevel: regime.minimumTrustLevel,
                    aiActClassification: regime.aiActClassification,
                    bundles: policySet.sourceBundles,
                }, "Gateway regime decision");
            const intent = await this.intentService.submit(submission, enriched);
            return { intent, regime, jurisdictionContext: jCtx, policySet, warnings };
        }
        catch (error) {
            if (error instanceof GatewayConflictError)
                throw error;
            logger.error({ error: error instanceof Error ? error.message : "Unknown" }, "Gateway error - falling through");
            const intent = await this.intentService.submit(submission, options);
            const result = this.createPassthroughResult(intent);
            result.warnings.push("Gateway degraded: " +
                (error instanceof Error ? error.message : "Unknown"));
            return result;
        }
    }
    resolveRegime(ctx, metadata) {
        const tenantId = extractTenantId(ctx);
        const cached = this.getCachedRegime(tenantId);
        if (cached)
            return {
                regime: cached.regime,
                jurisdictionContext: cached.jurisdictionContext,
                policySet: cached.policySet,
            };
        const jCtx = this.jurisdictionResolver.resolve(ctx, metadata);
        const tConfig = this.jurisdictionResolver.getTenantConfig(tenantId);
        const policySet = this.policyComposer.compose(jCtx, tConfig?.customPolicyBundles);
        const regime = this.regimeSelector.select(jCtx, policySet);
        this.cacheRegime(tenantId, jCtx, regime, policySet);
        return { regime, jurisdictionContext: jCtx, policySet };
    }
    registerTenantConfig(tenantId, config) {
        this.jurisdictionResolver.registerTenantConfig(tenantId, config);
        this.invalidateTenantCache(tenantId);
    }
    getActiveRegime(tenantId) {
        return this.getCachedRegime(tenantId)?.regime;
    }
    clearCache() {
        this.cache.clear();
    }
    getIntentService() {
        return this.intentService;
    }
    getConfig() {
        return { ...this.config };
    }
    createPassthroughResult(intent) {
        return {
            intent,
            regime: {
                regimeId: "regime-passthrough",
                name: "passthrough",
                jurisdictions: [this.config.defaultJurisdiction],
                policyNamespaces: [],
                cryptoSuite: "standard",
                proofAnchoring: "database",
                auditRetentionDays: 365,
                consentModel: "implicit",
                escalationMode: "flag-review",
                dataResidency: "global",
                externalServicesAllowed: true,
                minimumTrustLevel: 2,
                conformityAssessmentRequired: false,
                transparencyRequired: false,
                metadata: {},
            },
            jurisdictionContext: {
                primaryJurisdictions: [this.config.defaultJurisdiction],
                industry: this.config.defaultIndustry,
                dataResidency: "global",
                crossBorderTransfer: false,
                source: "default",
            },
            policySet: {
                constraints: [],
                sourceBundles: [],
                resolvedConflicts: [],
                unresolvedConflicts: [],
                isValid: true,
                composedAt: Date.now(),
            },
            warnings: [],
        };
    }
    getCacheKey(tenantId, js) {
        const h = js
            ? createHash("sha256")
                .update(JSON.stringify([...js].sort()))
                .digest("hex")
                .substring(0, 12)
            : "default";
        return tenantId + ":" + h;
    }
    cacheRegime(tenantId, ctx, regime, policySet) {
        this.cache.set(this.getCacheKey(tenantId, ctx.primaryJurisdictions), {
            regime,
            policySet,
            jurisdictionContext: ctx,
            cachedAt: Date.now(),
        });
    }
    getCachedRegime(tenantId) {
        for (const [key, entry] of this.cache) {
            if (key.startsWith(tenantId + ":")) {
                if (Date.now() - entry.cachedAt > this.config.regimeCacheTtlMs) {
                    this.cache.delete(key);
                    return undefined;
                }
                return entry;
            }
        }
        return undefined;
    }
    invalidateTenantCache(tenantId) {
        for (const key of [...this.cache.keys()]) {
            if (key.startsWith(tenantId + ":"))
                this.cache.delete(key);
        }
    }
}
export function createIntentGateway(intentService, config) {
    return new IntentGateway(intentService, config);
}
export { JurisdictionResolver } from "./jurisdiction-resolver.js";
export { PolicyComposer } from "./policy-composer.js";
export { RegimeSelector } from "./regime-selector.js";
export { AiActClassifier } from "./ai-act-classifier.js";
export { DEFAULT_GATEWAY_CONFIG } from "./types.js";
//# sourceMappingURL=index.js.map