/**
 * FeatureAgentSupervisorGateEvaluator
 *
 * Bridges the feature-agent worker's `waiting_approval` transition with
 * the {@link EvaluateSupervisorDecisionUseCase} (spec 093, task 29).
 *
 * On every approval-gate interrupt the worker calls
 * {@link evaluateForGate}. The evaluator:
 *
 *  1. Resolves the configured {@link SupervisorPolicy} for the
 *     (scopeType, scopeId, featureId) scope. When no policy is configured the call
 *     is a no-op — pure additive behaviour preserves the existing
 *     human-only path (NFR-14).
 *  2. Computes the effective per-gate autonomy: a `gateAuthorityJson`
 *     entry overrides the policy's default `autonomyLevel`.
 *  3. Calls {@link EvaluateSupervisorDecisionUseCase} which writes the
 *     {@link SupervisorDecision} row and mirrors it to the audit log.
 *  4. In **autonomous** mode for the gate AND when the supervisor's
 *     verdict is `approve` / `reject`, invokes
 *     {@link ApproveAgentRunUseCase} or {@link RejectAgentRunUseCase}
 *     with `actor = supervisor:<supervisorRunId>` so the existing gate
 *     state machine resolves the gate without further human action.
 *  5. In **advisory** and **co-sign** modes the decision is recorded
 *     but the gate stays in `waiting_approval`. The user still drives
 *     the resolution (user always wins). Co-sign awaits both votes by
 *     leaving the gate open for the user — the supervisor's vote is
 *     visible via `activity_log` but does not auto-close.
 *
 * Failures inside the evaluator MUST NOT crash the worker: the gate
 * already transitioned to `waiting_approval` before this hook runs, so
 * a swallowed error degrades to today's user-only flow (FR-22 fail
 * safe).
 */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
import { inject, injectable } from 'tsyringe';
import { randomUUID } from 'node:crypto';
import { ApproveAgentRunUseCase } from '../../../../application/use-cases/agents/approve-agent-run.use-case.js';
import { EvaluateSupervisorDecisionUseCase } from '../../../../application/use-cases/agents/evaluate-supervisor-decision.use-case.js';
import { GetSupervisorPolicyUseCase } from '../../../../application/use-cases/agents/get-supervisor-policy.use-case.js';
import { RejectAgentRunUseCase } from '../../../../application/use-cases/agents/reject-agent-run.use-case.js';
import { SupervisorAutonomy, SupervisorVerdict, } from '../../../../domain/generated/output.js';
import { supervisorActor } from '../../../../domain/value-objects/supervisor-actor.js';
const DEFAULT_GATE_ID = 'gate';
let FeatureAgentSupervisorGateEvaluator = class FeatureAgentSupervisorGateEvaluator {
    applicationRepo;
    getPolicy;
    evaluateDecision;
    approveAgentRun;
    rejectAgentRun;
    constructor(applicationRepo, getPolicy, evaluateDecision, approveAgentRun, rejectAgentRun) {
        this.applicationRepo = applicationRepo;
        this.getPolicy = getPolicy;
        this.evaluateDecision = evaluateDecision;
        this.approveAgentRun = approveAgentRun;
        this.rejectAgentRun = rejectAgentRun;
    }
    async evaluateForGate(input) {
        try {
            const { scopeType, scopeId } = await this.resolveScope(input.repositoryPath);
            const policy = await this.getPolicy.execute({
                scopeType,
                scopeId,
                featureId: input.featureId,
            });
            if (!policy) {
                // No supervisor configured for this scope. The flag-off short
                // circuit further down inside EvaluateSupervisorDecisionUseCase
                // still applies, but exiting here avoids generating a
                // supervisorRunId and a sourceEventId we don't need.
                return { evaluated: false, autoResolved: false };
            }
            const gateId = input.interruptNode ?? DEFAULT_GATE_ID;
            const supervisorRunId = randomUUID();
            const sourceEventId = `gate:${input.runId}:${gateId}`;
            const result = await this.evaluateDecision.execute({
                event: {
                    kind: 'gate',
                    scopeType,
                    scopeId,
                    featureId: input.featureId,
                    agentRunId: input.runId,
                    gateId,
                    sourceEventId,
                },
                supervisorRunId,
            });
            if (!result.evaluated || !result.decision) {
                return { evaluated: false, autoResolved: false };
            }
            const effectiveAutonomy = resolveEffectiveAutonomy(policy, gateId);
            const verdict = result.decision.verdict;
            const autoResolved = effectiveAutonomy === SupervisorAutonomy.autonomous &&
                (await this.applyAutonomousVerdict(input.runId, verdict, supervisorRunId));
            return {
                evaluated: true,
                effectiveAutonomy,
                verdict,
                autoResolved,
            };
        }
        catch {
            // Supervisor errors must not block the gate — fall back to the
            // existing human-only path (FR-22).
            return { evaluated: false, autoResolved: false };
        }
    }
    async applyAutonomousVerdict(runId, verdict, supervisorRunId) {
        const actor = supervisorActor(supervisorRunId);
        if (verdict === SupervisorVerdict.approve) {
            const out = await this.approveAgentRun.execute(runId, undefined, actor);
            return out.approved === true;
        }
        if (verdict === SupervisorVerdict.reject) {
            const out = await this.rejectAgentRun.execute(runId, 'Supervisor rejected (autonomous mode)', undefined, actor);
            return out.rejected === true;
        }
        // advise / escalate stay non-resolving in autonomous mode too — they
        // signal "human needed" and we leave the gate open.
        return false;
    }
    async resolveScope(repositoryPath) {
        try {
            const app = await this.applicationRepo.findByPath(repositoryPath);
            if (app?.id)
                return { scopeType: 'app', scopeId: app.id };
        }
        catch {
            // Fall through to repo-based scope.
        }
        return { scopeType: 'repo', scopeId: repositoryPath };
    }
};
FeatureAgentSupervisorGateEvaluator = __decorate([
    injectable(),
    __param(0, inject('IApplicationRepository')),
    __param(3, inject(ApproveAgentRunUseCase)),
    __param(4, inject(RejectAgentRunUseCase)),
    __metadata("design:paramtypes", [Object, GetSupervisorPolicyUseCase,
        EvaluateSupervisorDecisionUseCase,
        ApproveAgentRunUseCase,
        RejectAgentRunUseCase])
], FeatureAgentSupervisorGateEvaluator);
export { FeatureAgentSupervisorGateEvaluator };
/**
 * Resolves the per-gate autonomy override stored as JSON on
 * {@link SupervisorPolicy.gateAuthorityJson}. The map is keyed by gate
 * id (matching the LangGraph node name, e.g. `prd`, `plan`, `merge`).
 *
 * Exported so the unit test can exercise the parsing rules without
 * spinning up the full evaluator.
 */
export function resolveEffectiveAutonomy(policy, gateId) {
    if (!policy.gateAuthorityJson)
        return policy.autonomyLevel;
    try {
        const parsed = JSON.parse(policy.gateAuthorityJson);
        const override = parsed[gateId];
        if (typeof override === 'string' && isSupervisorAutonomy(override)) {
            return override;
        }
    }
    catch {
        // Malformed JSON falls back to the policy default.
    }
    return policy.autonomyLevel;
}
function isSupervisorAutonomy(value) {
    return (value === SupervisorAutonomy.advisory ||
        value === SupervisorAutonomy.cosign ||
        value === SupervisorAutonomy.autonomous);
}
