/**
 * AnswerAgentQuestionUseCase
 *
 * Records an answer for a pending {@link AgentQuestion} and:
 *  - validates the answer against the question's options when present,
 *  - transitions status to `answered`,
 *  - resolves the matching {@link IDeferredQuestionRegistry} entry so the
 *    SDK V2 `canUseTool` callback awaiting the answer returns,
 *  - for background-emitted questions tied to an approval gate, forwards
 *    `approve` / `reject` answers to the existing
 *    {@link ApproveAgentRunUseCase} / {@link RejectAgentRunUseCase} so the
 *    underlying gate state machine remains the single source of truth.
 *
 * Gate-linkage detection: a question is treated as gate-linked when its
 * `agentRunId` references a run currently in `waitingApproval` AND the
 * caller's answer matches the gate-vocabulary (`approve` / `reject`).
 * This keeps the unified-inbox surface backwards-compatible with the
 * existing approval flow without inventing a parallel pause primitive.
 */
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 { AgentQuestionStatus, AgentRunStatus, } from '../../../domain/generated/output.js';
import { ApproveAgentRunUseCase } from './approve-agent-run.use-case.js';
import { RejectAgentRunUseCase } from './reject-agent-run.use-case.js';
/** Canonical approve/reject vocabulary used by gate-linked questions. */
const GATE_APPROVE_ANSWERS = new Set(['approve', 'approved', 'yes']);
const GATE_REJECT_ANSWERS = new Set(['reject', 'rejected', 'no']);
let AnswerAgentQuestionUseCase = class AnswerAgentQuestionUseCase {
    questionRepository;
    deferredRegistry;
    settings;
    agentRunRepository;
    approveAgentRun;
    rejectAgentRun;
    constructor(questionRepository, deferredRegistry, settings, agentRunRepository, approveAgentRun, rejectAgentRun) {
        this.questionRepository = questionRepository;
        this.deferredRegistry = deferredRegistry;
        this.settings = settings;
        this.agentRunRepository = agentRunRepository;
        this.approveAgentRun = approveAgentRun;
        this.rejectAgentRun = rejectAgentRun;
    }
    async execute(input) {
        const flagOn = await this.isCollaborationEnabled();
        if (!flagOn)
            return { enabled: false, forwardedToGate: false };
        const existing = await this.questionRepository.findById(input.appId, input.questionId);
        if (!existing)
            return { enabled: true, forwardedToGate: false };
        if (existing.status !== AgentQuestionStatus.pending) {
            return { enabled: true, question: existing, forwardedToGate: false };
        }
        validateAnswerAgainstOptions(existing, input.answer);
        const now = new Date();
        await this.questionRepository.updateStatus(input.appId, input.questionId, AgentQuestionStatus.answered, {
            answer: input.answer,
            answeredBy: input.answeredBy,
            answeredAt: now,
        });
        // Resolve any in-process awaiter so the SDK callback returns.
        if (this.deferredRegistry.has(input.questionId)) {
            this.deferredRegistry.resolve(input.questionId, input.answer);
        }
        // Forward to the approval-gate use case when the question is gate-linked.
        const forwardedToGate = await this.maybeForwardToGate(existing, input);
        const updated = await this.questionRepository.findById(input.appId, input.questionId);
        return { enabled: true, question: updated ?? existing, forwardedToGate };
    }
    async maybeForwardToGate(question, input) {
        const verdict = mapAnswerToGateVerdict(input.answer);
        if (!verdict)
            return false;
        const run = await this.agentRunRepository.findById(question.agentRunId);
        if (!run || run.status !== AgentRunStatus.waitingApproval)
            return false;
        if (verdict === 'approve') {
            await this.approveAgentRun.execute(run.id);
        }
        else {
            await this.rejectAgentRun.execute(run.id, input.answer);
        }
        return true;
    }
    async isCollaborationEnabled() {
        const settings = await this.settings.load();
        return settings?.featureFlags?.collaboration === true;
    }
};
AnswerAgentQuestionUseCase = __decorate([
    injectable(),
    __param(0, inject('IAgentQuestionRepository')),
    __param(1, inject('IDeferredQuestionRegistry')),
    __param(2, inject('ISettingsRepository')),
    __param(3, inject('IAgentRunRepository')),
    __param(4, inject(ApproveAgentRunUseCase)),
    __param(5, inject(RejectAgentRunUseCase)),
    __metadata("design:paramtypes", [Object, Object, Object, Object, ApproveAgentRunUseCase,
        RejectAgentRunUseCase])
], AnswerAgentQuestionUseCase);
export { AnswerAgentQuestionUseCase };
function validateAnswerAgainstOptions(question, answer) {
    if (!question.optionsJson)
        return;
    let options;
    try {
        options = JSON.parse(question.optionsJson);
    }
    catch {
        return; // Malformed options column; trust the answer rather than rejecting.
    }
    if (!Array.isArray(options) || options.length === 0)
        return;
    if (!options.includes(answer)) {
        throw new Error(`AnswerAgentQuestion: answer "${answer}" is not one of the allowed options for question ${question.id}`);
    }
}
function mapAnswerToGateVerdict(answer) {
    const normalized = answer.trim().toLowerCase();
    if (GATE_APPROVE_ANSWERS.has(normalized))
        return 'approve';
    if (GATE_REJECT_ANSWERS.has(normalized))
        return 'reject';
    return null;
}
