/**
 * @internal
 * consistency/rules/r6-plan-approval.mjs — R6 (C21).
 *
 * Enforces the plan-mode approval handshake: when the task explicitly opted
 * into Plan Mode (task.execution_mode === 'plan-mode') and execution has
 * actually started (build-progress.json present), there must be an approved
 * plan_approval.json whose stored hashes still match the current spec/plan.
 *
 * Skips when:
 *   - task.execution_mode !== 'plan-mode' (other modes don't require approval).
 *   - build-progress.json is absent (execution hasn't started yet).
 *
 * Fails when:
 *   - plan_approval.json is missing.
 *   - decision !== 'approved' (rejected or revise also fail — execution
 *     started without a green light).
 *   - plan_hash drift: stored plan_hash differs from current sha256 of
 *     implementation_plan.json (plan was edited post-approval).
 *   - spec_hash drift: same for spec.md.
 *
 * Severity: error. Stages: execute, verify, ship.
 */

import { registerRule } from '../registry.mjs'

const rule = {
	id: 'r6-plan-approval',
	severity: 'error',
	stages: ['execute', 'verify', 'ship'],
	description: 'Plan Mode tasks have an approved plan_approval.json with intact hashes.',
	async check({ parsed }) {
		const executionMode = parsed?.task?.execution_mode ?? null
		if (executionMode !== 'plan-mode') {
			return {
				status: 'skip',
				drift: [],
				reason: `task.execution_mode is ${executionMode ?? 'unset'}, not plan-mode`,
			}
		}
		if (!parsed?.progress?.present) {
			return {
				status: 'skip',
				drift: [],
				reason: 'build-progress.json not present (execution has not started)',
			}
		}
		if (!parsed?.plan_approval?.present) {
			return {
				status: 'fail',
				drift: [
					{
						reason: 'plan_approval.json is missing — Plan Mode requires explicit approval',
					},
				],
				reason: 'plan_approval.json missing while execution is in progress',
			}
		}
		const decision = parsed.plan_approval.decision
		if (decision !== 'approved') {
			return {
				status: 'fail',
				drift: [
					{
						decision,
						reason: `plan_approval.decision is "${decision}" — execution requires "approved"`,
					},
				],
				reason: `plan_approval.decision is "${decision}", expected "approved"`,
			}
		}
		const drift = []
		const storedPlanHash = parsed.plan_approval.plan_hash
		const currentPlanHash = parsed.plan?.sha256 ?? null
		if (storedPlanHash && currentPlanHash && storedPlanHash !== currentPlanHash) {
			drift.push({
				file: 'implementation_plan.json',
				stored_hash: storedPlanHash,
				current_hash: currentPlanHash,
				reason: 'plan_hash drift — implementation_plan.json was edited after approval',
			})
		}
		const storedSpecHash = parsed.plan_approval.spec_hash
		const currentSpecHash = parsed.spec?.sha256 ?? null
		if (storedSpecHash && currentSpecHash && storedSpecHash !== currentSpecHash) {
			drift.push({
				file: 'spec.md',
				stored_hash: storedSpecHash,
				current_hash: currentSpecHash,
				reason: 'spec_hash drift — spec.md was edited after approval',
			})
		}
		if (drift.length > 0) {
			return {
				status: 'fail',
				drift,
				reason: `${drift.length} hash drift entry(ies) — re-record plan-approval after edits`,
			}
		}
		return {
			status: 'pass',
			drift: [],
			reason: 'plan_approval.json approved and hashes match current artifacts',
		}
	},
}

registerRule(rule)
export default rule
