import { randomUUID } from 'crypto';
import { nexusEventBus } from '../../engines/event-bus.js';
import { planTask } from '../../engines/task-planner.js';
import { parseMandateSignals } from './intent-parser.js';
import { matchNPAssets } from './asset-matcher.js';
import { insertStrikeTeam, insertMission, getStrikeTeam } from '../missions/crud.js';
import { insertOperative, updateOperativeMission } from '../operatives/crud.js';
import { SynapseConfig } from '../config.js';
import { safePublish } from '../coordination/safe-publish.js';
function unique(values) {
    return [...new Set(values)];
}
function boundedRequestedOperatives(opts) {
    const requested = Number(opts.maxOperatives ?? SynapseConfig.maxOpsPerTeam);
    const safeRequested = Number.isFinite(requested) && requested > 0 ? Math.floor(requested) : SynapseConfig.maxOpsPerTeam;
    return Math.max(1, Math.min(safeRequested, SynapseConfig.maxOpsPerTeam));
}
function decideMandateOperativeCount(signals, matched, missionTitles, opts) {
    const requested = boundedRequestedOperatives(opts);
    const evidenceCount = Math.max(matched.skills.length, matched.specialists.length, missionTitles.length);
    const complexityFloor = signals.complexity === 'read' ? 1 : 2;
    return Math.max(1, Math.min(requested, Math.max(evidenceCount || 1, complexityFloor)));
}
function deriveMissionTitles(mandateText, complexity, hints, planner) {
    const plannerHints = [
        ...planner.plannerState.selectedSpecialists.map((specialist) => `Coordinate with ${specialist.name}`),
        ...planner.plannerState.selectedWorkflows.map((workflow) => `Execute workflow: ${workflow}`),
        ...planner.task.successCriteria,
    ];
    const normalized = unique([...hints, ...plannerHints]
        .map((entry) => entry.trim())
        .filter((entry) => entry.length > 10)).slice(0, Math.max(1, planner.task.workers));
    if (normalized.length > 0)
        return normalized;
    return [`${complexity.toUpperCase()}: ${mandateText}`];
}
export async function executeMandatePipeline(db, mandateText, providers, opts = {}) {
    const signals = parseMandateSignals(mandateText);
    const matched = matchNPAssets(signals, providers.skillRuntime.listArtifacts());
    const planner = planTask({
        goal: mandateText,
        files: [],
        workers: Math.max(2, boundedRequestedOperatives(opts)),
        roles: ['planner', 'coder'],
        strategies: ['standard'],
        verifyCommands: [],
        successCriteria: signals.subGoalHints,
        rollbackPolicy: 'patch-revert',
        timeoutMs: 120_000,
        skillPolicy: { mode: 'session-only', allowMutateSkills: true },
        backendSelectors: {},
        skillNames: matched.skills.slice(0, 5).map((skill) => skill.name),
        workflowSelectors: [],
        hookSelectors: [],
        automationSelectors: [],
        connectorBindings: [],
        actions: [],
        inlineSkills: [],
        promotionPolicy: { autoPromoteSkills: false, autoPromoteWorkflows: false, globalThreshold: 0.9 },
        derivationPolicy: { mode: 'manual' },
        checkpointPolicy: [],
        backendMode: 'default',
        shieldPolicy: 'balanced',
        memoryPolicy: { mode: 'balanced', quarantineTag: '#quarantine' },
        crewSelectors: [],
        specialistSelectors: matched.specialists.map((specialist) => specialist.specialistId),
        optimizationProfile: 'standard',
        reviewPolicy: { mode: 'runtime-only' },
        releasePolicy: { mode: 'skip' },
        continuationPolicy: { mode: 'manual' },
        continuationDepth: 0,
        suppressedAutomationIds: [],
        executionMode: 'autonomous',
        manualOverrides: [],
    });
    const missionTitles = deriveMissionTitles(mandateText, signals.complexity, signals.subGoalHints, planner);
    const maxOps = decideMandateOperativeCount(signals, matched, missionTitles, opts);
    const budget = opts.budgetUsd ?? SynapseConfig.defaultBudgetUsd;
    const team = db.transaction(() => {
        const teamId = randomUUID();
        // Ensure Architects creates a blueprint + worklist for this team (auto-wiring)
        const worklistId = providers.coordination?.getWorklistId(teamId) ?? null;
        const blueprintId = worklistId ? `implicit-blueprint:${teamId}` : null;
        let leadOperativeId = null;
        const hiringPlan = [];
        const missionPlan = [];
        const operativeIds = Array.from({ length: maxOps }, (_, index) => {
            const skill = matched.skills.length > 0 ? matched.skills[index % matched.skills.length] : undefined;
            const specialist = matched.specialists.length > 0 ? matched.specialists[index % matched.specialists.length] : null;
            const operative = insertOperative(db, {
                id: randomUUID(),
                name: `operative-${teamId.slice(0, 4)}-${index + 1}`,
                roleTitle: specialist?.name ?? skill?.name ?? 'Operative',
                skillId: skill?.name ?? null,
                specialistId: specialist?.specialistId ?? null,
                budgetCapUsd: budget / maxOps,
                strikeTeamId: teamId,
                sortieIntervalMs: SynapseConfig.sortieIntervalMs,
                origin: 'mandate',
                // First operative is the team lead; subsequent members report to it.
                reportsToOperativeId: index === 0 ? null : leadOperativeId,
            });
            if (index === 0)
                leadOperativeId = operative.id;
            hiringPlan.push({
                operativeId: operative.id,
                name: operative.name,
                roleTitle: operative.roleTitle,
                skillId: operative.skillId,
                specialistId: operative.specialistId,
                reportsToOperativeId: operative.reportsToOperativeId,
                budgetCapUsd: operative.budgetCapUsd,
            });
            nexusEventBus.emit('synapse.operative.hired', {
                operativeId: operative.id,
                name: operative.name,
                skillId: operative.skillId,
                specialistId: operative.specialistId,
                roleTitle: operative.roleTitle,
                reportsToOperativeId: operative.reportsToOperativeId,
                strikeTeamId: teamId,
            });
            return operative.id;
        });
        const missionIds = missionTitles.map((title, index) => {
            const operativeId = operativeIds[index % operativeIds.length];
            const mission = insertMission(db, {
                id: randomUUID(),
                ancestryPath: [teamId],
                correlationId: teamId,
                strikeTeamId: teamId,
                title,
                complexity: signals.complexity,
                status: 'open',
                assignedOperativeId: operativeId,
                requiresApprovalGate: signals.complexity === 'mutate',
                approvalScope: signals.complexity === 'mutate' ? 'crew' : 'mission',
                approvalScopeId: signals.complexity === 'mutate' ? teamId : undefined,
                budgetScope: 'crew',
                budgetScopeId: teamId,
            });
            updateOperativeMission(db, operativeId, mission.id, teamId);
            missionPlan.push({
                missionId: mission.id,
                title: mission.title,
                assignedOperativeId: operativeId,
                complexity: mission.complexity,
                requiresApprovalGate: mission.requiresApprovalGate,
            });
            nexusEventBus.emit('synapse.mission.assigned', {
                operativeId,
                missionId: mission.id,
                title: mission.title,
                strikeTeamId: teamId,
                worklistId,
                correlationId: mission.correlationId ?? mission.id,
            });
            safePublish(providers.coordination, {
                phase: 'mandate',
                summary: `Mission assigned: ${mission.title}`,
                strikeTeamId: teamId,
                worklistId,
                workItemId: mission.id,
                operativeId,
                correlationId: mission.correlationId ?? mission.id,
                status: 'assigned',
            }, 'mandate');
            return mission.id;
        });
        const selectionSummary = {
            domains: signals.domains,
            complexity: signals.complexity,
            skills: unique(matched.skills.slice(0, maxOps).map((skill) => skill.name).filter(Boolean)),
            specialists: unique(matched.specialists.slice(0, maxOps).map((specialist) => specialist.name).filter(Boolean)),
            workflows: unique(planner.plannerState.selectedWorkflows),
            operativeCount: operativeIds.length,
            missionCount: missionIds.length,
        };
        insertStrikeTeam(db, {
            id: teamId,
            mandateText,
            operativeIds,
            missionIds,
            blueprintId,
            status: 'active',
        });
        nexusEventBus.emit('synapse.striketeam.deployed', {
            strikeTeamId: teamId,
            operativeCount: operativeIds.length,
            missionCount: missionIds.length,
            selectionSummary,
            worklistId,
            correlationId: teamId,
        });
        safePublish(providers.coordination, {
            phase: 'mandate',
            summary: `Strike team deployed for mandate: ${mandateText.slice(0, 120)}`,
            strikeTeamId: teamId,
            worklistId,
            correlationId: teamId,
            status: 'deployed',
        }, 'mandate');
        providers.memory.store(`[Synapse:Mandate] ${mandateText}`, 0.85, ['#synapse', '#mandate', `#team:${teamId}`], undefined, 0, {
            provenance: {
                source: 'runtime',
                containerTags: [`#team:${teamId}`, ...(worklistId ? [`#worklist:${worklistId}`] : [])],
            },
        });
        return {
            ...getStrikeTeam(db, teamId),
            selectionSummary,
            hiringPlan,
            missionPlan,
        };
    })();
    nexusEventBus.emit('synapse.striketeam.finished', {
        strikeTeamId: team.id,
        intent: signals.complexity,
        outcome: 'completed',
    });
    return team;
}
