/**
 * subagent-inheritance.js — parent mode envelope for subagent dispatch.
 *
 * Purpose: keep delegated agents inside the parent's provider, model-mode, and
 * permission-profile constraints so swarms cannot silently widen authority.
 *
 * Consumer: `subagent` extension before it starts worker processes.
 */

import { getAutoSession } from "./auto/session.js";
import { recordCounter } from "./metrics-central.js";
import {
	resolveModelMode,
	resolvePermissionProfile,
	resolveRunControlMode,
	resolveWorkMode,
} from "./operating-model.js";
import {
	isHeavyModelId,
	isProviderAllowedByLists,
} from "./preferences-models.js";
import { logWarning } from "./workflow-logger.js";

function providerFromModelId(modelId) {
	if (!modelId || typeof modelId !== "string") return null;
	const [provider] = modelId.split("/", 1);
	return provider && provider !== modelId ? provider : null;
}

/**
 * Build an inheritance envelope from the current parent session.
 *
 * Purpose: capture orthogonal mode axes and provider policy once, then pass the
 * same envelope through validation and child-process environment.
 *
 * Consumer: `subagent` tool execution.
 */
export function buildSubagentInheritanceEnvelope({
	mode,
	preferences = {},
	surface,
} = {}) {
	let sessionMode = mode ?? {};
	if (!mode) {
		try {
			const session = getAutoSession();
			sessionMode = session.getMode?.() ?? {};
		} catch {
			// In subagent process or test context — use defaults
		}
	}

	return {
		workMode: resolveWorkMode(sessionMode.workMode),
		modelMode: resolveModelMode(sessionMode.modelMode),
		permissionProfile: resolvePermissionProfile(sessionMode.permissionProfile),
		runControl: resolveRunControlMode(sessionMode.runControl),
		surface: surface ?? sessionMode.surface ?? "tui",
		allowedProviders: preferences.allowed_providers ?? null,
		blockedProviders: preferences.blocked_providers ?? null,
	};
}

/**
 * Validate a proposed subagent dispatch against the parent envelope.
 *
 * Purpose: reject delegated work that would bypass parent provider allowlists,
 * fast-mode routing posture, or restricted mutation rules.
 *
 * Consumer: `subagent` tool before single, chain, parallel, debate, or
 * background dispatch.
 */
export function validateSubagentDispatch(envelope, proposal) {
	const modelId = proposal.model ?? null;
	const provider = proposal.provider ?? providerFromModelId(modelId);

	// Record dispatch attempt
	recordCounter("sf_subagent_dispatch_total", {
		work_mode: envelope.workMode,
		permission_profile: envelope.permissionProfile,
	});

	if (
		provider &&
		!isProviderAllowedByLists(
			provider,
			envelope.allowedProviders,
			envelope.blockedProviders,
		)
	) {
		logWarning(
			"subagent-inheritance",
			`Blocked provider "${provider}" for subagent dispatch`,
		);
		recordCounter("sf_subagent_dispatch_blocked", {
			reason: "provider",
			work_mode: envelope.workMode,
			permission_profile: envelope.permissionProfile,
		});
		return {
			ok: false,
			reason: `Provider "${provider}" is blocked by parent provider policy`,
		};
	}

	if (envelope.modelMode === "fast" && isHeavyModelId(modelId)) {
		logWarning(
			"subagent-inheritance",
			`Blocked heavy model "${modelId}" in fast mode`,
		);
		recordCounter("sf_subagent_dispatch_blocked", {
			reason: "model_mode",
			work_mode: envelope.workMode,
			permission_profile: envelope.permissionProfile,
		});
		return {
			ok: false,
			reason: `Model mode "fast" blocks heavy subagent model "${modelId}"`,
		};
	}

	if (envelope.permissionProfile === "restricted") {
		const proposedTools = proposal.tools ?? [];
		const RESTRICTED_TOOLS = new Set([
			"write",
			"edit",
			"bash",
			"mac_launch_app",
		]);
		const blocked = proposedTools.filter((toolName) =>
			RESTRICTED_TOOLS.has(toolName.toLowerCase()),
		);
		if (blocked.length > 0) {
			logWarning(
				"subagent-inheritance",
				`Blocked tools [${blocked.join(", ")}] in restricted mode`,
			);
			recordCounter("sf_subagent_dispatch_blocked", {
				reason: "permission_profile",
				work_mode: envelope.workMode,
				permission_profile: envelope.permissionProfile,
			});
			return {
				ok: false,
				reason: `Permission profile "restricted" blocks subagent tools: ${blocked.join(", ")}`,
			};
		}
	}

	recordCounter("sf_subagent_dispatch_allowed", {
		work_mode: envelope.workMode,
		permission_profile: envelope.permissionProfile,
	});
	return { ok: true };
}

/**
 * Return only the environment keys that carry parent inheritance.
 *
 * Purpose: let direct spawn and generated cmux launchers propagate the same
 * constraint envelope without copying the full parent environment.
 *
 * Consumer: `resolveSubagentLaunchSpec`.
 */
function buildSubagentInheritanceEnvPatch(envelope) {
	if (!envelope) return {};
	return {
		SF_PARENT_WORK_MODE: envelope.workMode,
		SF_PARENT_MODEL_MODE: envelope.modelMode,
		SF_PARENT_PERMISSION_PROFILE: envelope.permissionProfile,
		SF_PARENT_RUN_CONTROL: envelope.runControl,
		SF_PARENT_SURFACE: envelope.surface,
	};
}

/**
 * Apply parent inheritance keys to a process environment.
 *
 * Purpose: make spawned subagents aware of the parent posture for downstream
 * enforcement and diagnostics.
 *
 * Consumer: direct subagent process launch.
 */
export function applyInheritanceToEnv(envelope, env = process.env) {
	return {
		...env,
		...buildSubagentInheritanceEnvPatch(envelope),
	};
}

/**
 * Read parent inheritance from a child-process environment.
 *
 * Purpose: let subagent startup and diagnostics recover the parent posture
 * without reading parent-only session state.
 *
 * Consumer: subagent child process startup paths.
 */
export function readParentInheritanceFromEnv(env = process.env) {
	if (!env.SF_PARENT_WORK_MODE) return null;
	return {
		workMode: resolveWorkMode(env.SF_PARENT_WORK_MODE),
		modelMode: resolveModelMode(env.SF_PARENT_MODEL_MODE),
		permissionProfile: resolvePermissionProfile(
			env.SF_PARENT_PERMISSION_PROFILE,
		),
		runControl: resolveRunControlMode(env.SF_PARENT_RUN_CONTROL),
		surface: env.SF_PARENT_SURFACE ?? "tui",
	};
}
