/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { SfError } from '@salesforce/core';
import { addHandoffRecord, requestReview } from './orchestration-records.js';
import { resolveQualityContractWithDomain, validateHandoffContent, validateHandoffQuality, validateRequiredFields, } from './quality-contracts.js';
import { completeTask } from './task-state.js';
import { addEffortEstimate } from './workflow-effort.js';
import { PHASE_GATES, PHASE_TO_PROFILE } from './workflow-instructions.js';
export function resolveResponsibleRole(fromPhase, reviewResult) {
    if (reviewResult === 'changes')
        return PHASE_TO_PROFILE[fromPhase];
    return PHASE_TO_PROFILE[fromPhase];
}
export function buildGateBlockedNotification(storyId, fromPhase, toPhase, reason, reviewId) {
    return {
        storyId,
        blockedGate: `${fromPhase}→${toPhase}`,
        responsibleRole: PHASE_TO_PROFILE[fromPhase],
        reason,
        reviewId,
    };
}
export function closePhaseWithHandoff(cwd, run, fromPhase, toPhase, summary, evidenceIds, toProfileOverride, effortOptions) {
    const fromProfile = PHASE_TO_PROFILE[fromPhase];
    const toProfile = toProfileOverride ?? PHASE_TO_PROFILE[toPhase];
    const phaseRecord = run.phases.find((p) => p.phase === fromPhase);
    if (phaseRecord)
        completeTask(cwd, { id: phaseRecord.taskId, profile: fromProfile, evidenceIds });
    const handoff = addHandoffRecord(cwd, {
        summary,
        from: fromProfile,
        to: toProfile,
        taskIds: [run.storyId],
        evidenceIds,
    });
    enforceQualityContract(cwd, run.storyId, fromPhase, fromProfile, summary, evidenceIds);
    const transitionKey = `${fromPhase}→${toPhase}`;
    const needsGate = run.gates === 'all' || (run.gates === 'phase' && PHASE_GATES.has(transitionKey));
    const workMode = deriveWorkMode(needsGate, run.gates);
    const effortRecord = addEffortEstimate(cwd, {
        storyId: run.storyId,
        phase: fromPhase,
        workMode,
        actualMinutes: effortOptions?.actualMinutes ?? deriveActualMinutes(phaseRecord),
        estimatedUnguidedMinutes: effortOptions?.estimatedUnguidedMinutes ?? null,
        confidence: effortOptions?.confidence ?? 'medium',
        rationale: effortOptions?.rationale ?? `Phase ${fromPhase} closed via ${transitionKey}`,
    });
    if (!needsGate)
        return { handoffId: handoff.id, effortId: effortRecord.id };
    const review = requestReview(cwd, {
        summary: `Gate review: ${transitionKey} for ${run.storyId}`,
        requester: fromProfile,
        reviewer: toProfile,
        gates: [transitionKey],
        taskIds: [run.storyId],
        evidenceIds: [handoff.id],
    });
    return { handoffId: handoff.id, reviewId: review.id, effortId: effortRecord.id };
}
function enforceQualityContract(cwd, storyId, fromPhase, fromProfile, summary, evidenceIds) {
    const qualityResult = validateHandoffQuality(cwd, storyId, fromPhase, fromProfile);
    const contentResult = validateHandoffContent(summary, evidenceIds);
    // Resolve the full contract with domain escalation for required-field validation
    const contract = resolveQualityContractWithDomain(cwd, fromPhase, fromProfile);
    const fieldsResult = validateRequiredFields(contract, new Set(evidenceIds));
    const effectiveMode = contract.mode;
    if (effectiveMode === 'block') {
        enforceBlockMode(qualityResult, contentResult);
        return;
    }
    // 'escalate' mode was removed — treat as 'warn' for backwards compatibility
    if (effectiveMode === 'warn') {
        emitQualityWarnings(qualityResult.violations, contentResult.warnings);
        if (fieldsResult.missing.length > 0) {
            const fieldWarnings = fieldsResult.missing.map((f) => `Missing required field "${f.field}": ${f.description}`);
            emitQualityWarnings([], fieldWarnings);
        }
    }
    // advisory mode: no action
}
function enforceBlockMode(qualityResult, contentResult) {
    if (!qualityResult.passed) {
        throw new SfError(`Quality contract violated (block mode): ${qualityResult.violations.join('; ')}`, 'QualityContractViolation');
    }
    if (!contentResult.valid) {
        throw new SfError(`Handoff content rejected (block mode): ${contentResult.warnings.join('; ')}`, 'HandoffContentRejected');
    }
}
function emitQualityWarnings(violations, contentWarnings) {
    for (const v of violations) {
        process.stderr.write(`[quality-contract warn] ${v}\n`);
    }
    for (const w of contentWarnings) {
        process.stderr.write(`[handoff-content warn] ${w}\n`);
    }
}
function deriveWorkMode(needsGate, gates) {
    if (needsGate)
        return 'ai_supervised';
    if (gates === 'none')
        return 'ai_autonomous';
    return 'ai_supervised';
}
function deriveActualMinutes(phaseRecord) {
    if (!phaseRecord?.startedAt)
        return null;
    const endMs = phaseRecord.completedAt ? new Date(phaseRecord.completedAt).getTime() : Date.now();
    return Math.round((endMs - new Date(phaseRecord.startedAt).getTime()) / 60_000);
}
//# sourceMappingURL=workflow-gates.js.map