/**
 * Swarm Role Agents — Purpose-built PersistentAgent subclasses for the default SF swarm topology.
 *
 * Purpose: provide ready-to-use agent roles (coordinator, worker, scout, reviewer, planner,
 * verifier, scribe, adversary) with preset tags and capabilities, and a factory function
 * that assembles a complete default swarm topology persisted to SQLite.
 *
 * Consumer: SwarmDispatchLayer, /sf swarm command, and any code needing a default
 * multi-agent topology without manually wiring individual agents.
 */

import { AgentSwarm, ManagerType } from "./agent-swarm.js";
import { PersistentAgent } from "./persistent-agent.js";

/**
 * Coordinator agent — owns routing and task dispatch across a worker pool.
 *
 * Purpose: provide a persistent orchestrator that routes incoming work to
 * the right worker based on message workMode, accumulates results, and
 * maintains swarm-level state in its core blocks.
 *
 * Consumer: createDefaultSwarm, SwarmDispatchLayer, and /sf swarm command.
 */
export class CoordinatorAgent extends PersistentAgent {
	/**
	 * @param {string} basePath
	 * @param {object} [options={}]
	 * @param {string} [options.name='coordinator']
	 * @param {string[]} [options.tags=[]]
	 */
	constructor(basePath, options = {}) {
		super(basePath, {
			name: options.name ?? "coordinator",
			role: "coordinator",
			tags: ["role:coordinator", "tier:persistent", ...(options.tags ?? [])],
			...options,
		});
	}

	/**
	 * Route an incoming message body to the right worker by reading its workMode field.
	 *
	 * Purpose: select a suitable worker from the swarm roster and forward the
	 * message so the coordinator does not block on task execution. Selection
	 * prefers agents tagged with `workMode:<value>`, falling back to any
	 * available worker-tier agent.
	 *
	 * Consumer: autonomous dispatch loops and /sf swarm run command.
	 *
	 * @param {AgentSwarm} swarm - the swarm containing candidate workers
	 * @param {object} messageBody - message body; `messageBody.workMode` guides selection
	 * @param {object} [metadata={}] - forwarded as message metadata
	 * @returns {{ targetAgent: PersistentAgent, messageId: string } | null}
	 */
	routeToWorker(swarm, messageBody, metadata = {}) {
		const { workMode } = messageBody ?? {};
		const candidates = swarm.agents.filter((a) => {
			const id = a.identity;
			if (id.name === this._name) return false;
			if (!id.tags.includes("tier:worker")) return false;
			if (workMode && id.tags.includes(`workMode:${workMode}`)) return true;
			return !workMode;
		});

		// Prefer specialised match; fall back to first available worker.
		const specialised = workMode
			? candidates.filter((a) =>
					a.identity.tags.includes(`workMode:${workMode}`),
				)
			: [];
		const target = specialised[0] ?? candidates[0] ?? null;

		if (!target) return null;

		const messageId = this.send(target.identity.name, messageBody, metadata);
		return { targetAgent: target, messageId };
	}
}

/**
 * Worker agent — executes assigned build and repair tasks.
 *
 * Purpose: provide a general-purpose execution agent that accepts task
 * messages from a coordinator and runs them to completion.
 *
 * Consumer: createDefaultSwarm worker pool and direct task assignment.
 */
export class WorkerAgent extends PersistentAgent {
	constructor(basePath, options = {}) {
		super(basePath, {
			name: options.name ?? "worker",
			role: "worker",
			tags: ["role:worker", "tier:worker", ...(options.tags ?? [])],
			...options,
		});
	}
}

/**
 * Scout agent — discovers and surfaces information for the swarm.
 *
 * Purpose: provide a dedicated research/discovery agent whose results feed
 * into coordinator routing decisions and worker task context. Runs in an
 * isolated context with no side effects.
 *
 * Consumer: createDefaultSwarm and coordinator agents that need pre-fetched
 * context before delegating execution tasks.
 */
export class ScoutAgent extends PersistentAgent {
	constructor(basePath, options = {}) {
		super(basePath, {
			name: options.name ?? "scout",
			role: "scout",
			tags: ["role:scout", "tier:worker", ...(options.tags ?? [])],
			...options,
		});
	}
}

/**
 * Reviewer agent — critiques worker output against intent.
 *
 * Purpose: provide a fresh-context critique agent that receives completed
 * task output and either approves, requests revision, or escalates. Runs
 * without the worker's accumulated context so bias doesn't carry over.
 *
 * Consumer: createDefaultSwarm and any dispatch flow requiring a review
 * pass before accepting task output as final.
 */
export class ReviewerAgent extends PersistentAgent {
	constructor(basePath, options = {}) {
		super(basePath, {
			name: options.name ?? "reviewer",
			role: "reviewer",
			tags: ["role:reviewer", "tier:worker", ...(options.tags ?? [])],
			...options,
		});
	}
}

/**
 * Planner agent — generates milestone, slice, and task contracts.
 *
 * Purpose: own the plan workMode — translate bounded intent into PDD-backed
 * milestone/slice/task structures. Separated from coordinator so planning
 * doesn't consume coordinator context and remains independently restartable.
 *
 * Consumer: createDefaultSwarm, auto-dispatch plan-milestone / plan-slice /
 * refine-slice / replan-slice unit types.
 */
export class PlannerAgent extends PersistentAgent {
	constructor(basePath, options = {}) {
		super(basePath, {
			name: options.name ?? "planner",
			role: "planner",
			tags: ["role:planner", "tier:persistent", ...(options.tags ?? [])],
			...options,
		});
	}
}

/**
 * Verifier agent — runs gates, UAT, and evidence checks.
 *
 * Purpose: own the verify workMode — execute binary pass/fail checks
 * (gate-evaluate, validate-milestone, run-uat) without conflating them
 * with subjective review. Separated from reviewer so verification failures
 * produce actionable structured output rather than qualitative critique.
 *
 * Consumer: createDefaultSwarm and gate-runner dispatch paths.
 */
export class VerifierAgent extends PersistentAgent {
	constructor(basePath, options = {}) {
		super(basePath, {
			name: options.name ?? "verifier",
			role: "verifier",
			tags: ["role:verifier", "tier:worker", ...(options.tags ?? [])],
			...options,
		});
	}
}

/**
 * Scribe agent — writes and exports documentation.
 *
 * Purpose: own the document workMode — produce changelogs, spec exports,
 * ADRs, and user-facing docs from structured state. Separated from worker
 * so doc generation doesn't share a context window with implementation work.
 *
 * Consumer: createDefaultSwarm and rewrite-docs / promote-spec unit types.
 */
export class ScribeAgent extends PersistentAgent {
	constructor(basePath, options = {}) {
		super(basePath, {
			name: options.name ?? "scribe",
			role: "scribe",
			tags: ["role:scribe", "tier:worker", ...(options.tags ?? [])],
			...options,
		});
	}
}

/**
 * Adversary agent — red-teams plans and decisions.
 *
 * Purpose: own the challenge workMode — actively seek failure modes,
 * unexamined assumptions, and security gaps in plans or implementations.
 * Runs in adversarial framing so it doesn't default to agreement.
 *
 * Consumer: createDefaultSwarm and challenge-mode dispatch (future).
 */
export class AdversaryAgent extends PersistentAgent {
	constructor(basePath, options = {}) {
		super(basePath, {
			name: options.name ?? "adversary",
			role: "adversary",
			tags: ["role:adversary", "tier:worker", ...(options.tags ?? [])],
			...options,
		});
	}
}

/**
 * Create a complete default swarm topology.
 *
 * Purpose: assemble the full SF agent topology (coordinator + planner +
 * 2 workers + scout + reviewer + verifier + scribe + adversary) wired to a
 * shared MessageBus, with the agent_directory core block set on all agents.
 *
 * Consumer: SwarmDispatchLayer.getOrCreateSwarm() and autonomous dispatch bootstrap.
 *
 * @param {string} basePath
 * @param {object} [options={}]
 * @param {string} [options.swarmName='default']
 * @param {string} [options.managerType] - ManagerType value, default 'supervisor'
 */
export async function createDefaultSwarm(basePath, options = {}) {
	const coordinator = new CoordinatorAgent(basePath, { name: "coordinator" });
	const planner = new PlannerAgent(basePath, { name: "planner" });
	const workers = [
		new WorkerAgent(basePath, { name: "worker-1" }),
		new WorkerAgent(basePath, { name: "worker-2" }),
	];
	const scout = new ScoutAgent(basePath, { name: "scout" });
	const reviewer = new ReviewerAgent(basePath, { name: "reviewer" });
	const verifier = new VerifierAgent(basePath, { name: "verifier" });
	const scribe = new ScribeAgent(basePath, { name: "scribe" });
	const adversary = new AdversaryAgent(basePath, { name: "adversary" });

	const swarm = new AgentSwarm(basePath, {
		name: options.swarmName ?? "default",
		managerType: options.managerType ?? ManagerType.SUPERVISOR,
	});

	swarm.register(coordinator);
	swarm.register(planner);
	for (const worker of workers) swarm.register(worker);
	swarm.register(scout);
	swarm.register(reviewer);
	swarm.register(verifier);
	swarm.register(scribe);
	swarm.register(adversary);

	swarm.persist();

	return {
		swarm,
		coordinator,
		planner,
		workers,
		scout,
		reviewer,
		verifier,
		scribe,
		adversary,
	};
}
