import { withAliases } from '../lib/verbs.js';
import chalk from 'chalk';
import ora from 'ora';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { select, checkbox } from '@inquirer/prompts';
import { resolveAgentName, agentLabel } from '../lib/agents.js';
import { capableAgents } from '../lib/capabilities.js';
import { cloneRepo } from '../lib/git.js';
import { discoverWorkflowsFromRepo, installWorkflowCentrally, removeWorkflow, listInstalledWorkflows, listWorkflowsForAgent, removeWorkflowFromVersion, iterWorkflowsCapableVersions, } from '../lib/workflows.js';
import { getVersionHomePath, getGlobalDefault, syncResourcesToVersion, promptAgentVersionSelection, } from '../lib/installations/versions.js';
import { recordVersionResources, getUserWorkflowsDir } from '../lib/state.js';
import { isPromptCancelled, isInteractiveTerminal, requireInteractiveSelection, printWithPager, promptRemovalTargets, parseCommaSeparatedList, resolveAgentTargetsAutoInstalling, resolveListFilterOrExit, } from './utils.js';
import { showResourceList, buildTargetsSection, } from './resource-view.js';
/** Register the `agents workflows` command tree (list, view, add, remove). */
export function registerWorkflowsCommands(program) {
    const workflowsCmd = program
        .command('workflows')
        .description('Manage multi-agent pipeline workflows (WORKFLOW.md bundles)')
        .addHelpText('after', `
Workflows are directory bundles that define reusable named agent pipelines.
Run a workflow with:
  agents run <workflow-name> [prompt]

Structure:
  ~/.agents/workflows/<name>/
    WORKFLOW.md        required: YAML frontmatter + orchestrator system prompt
    subagents/*.md     optional: subagents the orchestrator can dispatch to
    skills/            optional: knowledge packs scoped to this workflow
    plugins/           optional: plugin bundles scoped to this workflow

Resolution: project > user > plugin (plugins/*/workflows/) > extra > system.
Pin a source with name@plugin or name@extra-alias (optional workflow: prefix).

Note: agents run defaults to --mode plan (read-only). For workflows that
write files, post comments, or otherwise mutate state, pass --mode edit or
--mode full or the run will deadlock at ExitPlanMode.

Examples:
  # See what workflows are available
  agents workflows list

  # Install from GitHub or a local directory
  agents workflows add gh:user/workflows
  agents workflows add ./code-review

  # Inspect a workflow's frontmatter and subagents
  agents workflows view code-review

  # Run it (workflow name goes in the agent slot)
  agents run code-review "review PR #42"

  # Run a workflow that posts comments / edits files
  agents run code-review --mode full "review PR #42 and post the review"

  # Remove from version homes (and central storage on second run)
  agents workflows remove code-review
`);
    withAliases(workflowsCmd
        .command('list [agent]'), 'list')
        .description('Show installed workflows and which agent versions they are synced to')
        .option('-a, --agent <agent>', 'Filter to a specific agent')
        .action(async (agentArg, options) => {
        const spinner = ora({ text: 'Loading...', isSilent: !process.stdout.isTTY }).start();
        const agentInput = agentArg || options.agent;
        let filterAgent;
        let filterVersion;
        if (agentInput) {
            const parts = agentInput.split('@');
            const resolved = resolveAgentName(parts[0]);
            if (!resolved) {
                spinner.stop();
                console.log(chalk.red(`Unknown agent: ${parts[0]}`));
                process.exit(1);
            }
            filterAgent = resolved;
            filterVersion = resolveListFilterOrExit(resolved, parts[1]);
        }
        const rows = buildWorkflowRows({ filterAgent, filterVersion });
        spinner.stop();
        await showResourceList({
            resourcePlural: 'workflows',
            resourceSingular: 'workflow',
            extraLabel: 'Agents',
            rows,
            emptyMessage: filterAgent
                ? `No workflows in central storage for ${agentLabel(filterAgent)}.`
                : 'No workflows in ~/.agents/workflows/. Add one with: agents workflows add gh:user/repo',
            centralPath: getUserWorkflowsDir(),
            filterAgent,
            filterVersion,
        });
    });
    workflowsCmd
        .command('add [source]')
        .description('Install workflows from a source (GitHub, local) or pick from central storage')
        .option('-a, --agents <list>', 'Targets: claude, claude@2.1.138, claude@all, all')
        .option('--names <list>', 'Workflow names from the source (comma-separated)')
        .option('-y, --yes', 'Skip confirmation prompts')
        .addHelpText('after', `
Examples:
  # Install from GitHub
  agents workflows add gh:user/workflows

  # Pluck specific workflows from a multi-workflow repo
  agents workflows add gh:user/workflows --names rdev,plan

  # Install a local workflow directory (must contain WORKFLOW.md)
  agents workflows add ./rdev

  # Install and sync to a specific version
  agents workflows add gh:user/workflows --agents claude@2.1.138

  # Install across every installed Claude version
  agents workflows add gh:user/workflows --agents claude@all
`)
        .action(async (source, options) => {
        try {
            let workflows;
            if (!source) {
                // Interactive: pick from central storage
                const installed = listInstalledWorkflows();
                if (installed.size === 0) {
                    console.log(chalk.yellow('No workflows in ~/.agents/workflows/'));
                    console.log(chalk.gray('\nTo add workflows from a repo:'));
                    console.log(chalk.cyan('  agents workflows add gh:user/repo'));
                    return;
                }
                if (!isInteractiveTerminal()) {
                    requireInteractiveSelection('Selecting workflows', [
                        'agents workflows add gh:user/repo',
                    ]);
                }
                const choices = Array.from(installed.values()).map(w => ({
                    value: w.name,
                    name: w.frontmatter.description
                        ? `${w.name}  ${chalk.gray(w.frontmatter.description.slice(0, 50))}`
                        : w.name,
                }));
                const selected = await checkbox({ message: 'Select workflows to sync', choices });
                if (selected.length === 0) {
                    console.log(chalk.gray('No workflows selected.'));
                    return;
                }
                workflows = selected.map(name => ({ name, path: installed.get(name).path }));
            }
            else {
                // Fetch from repo or local path
                const spinner = ora('Fetching workflows...').start();
                const isGitRepo = source.startsWith('gh:') || source.startsWith('git:') ||
                    source.startsWith('https://') || source.startsWith('http://');
                let localPath;
                if (isGitRepo) {
                    const result = await cloneRepo(source);
                    localPath = result.localPath;
                    spinner.succeed('Repository cloned');
                }
                else {
                    localPath = source.startsWith('~')
                        ? path.join(os.homedir(), source.slice(1))
                        : path.resolve(source);
                    if (!fs.existsSync(localPath)) {
                        spinner.fail(`Path not found: ${localPath}`);
                        return;
                    }
                    spinner.succeed('Using local path');
                }
                let discovered = discoverWorkflowsFromRepo(localPath);
                if (discovered.length === 0) {
                    console.log(chalk.yellow('No workflows found (looking for WORKFLOW.md files)'));
                    return;
                }
                // --names filter: pluck specific workflows from a multi-workflow source.
                const requestedNames = parseCommaSeparatedList(options.names);
                if (requestedNames.length > 0) {
                    const discoveredNames = new Set(discovered.map((w) => w.name));
                    const missing = requestedNames.filter((n) => !discoveredNames.has(n));
                    if (missing.length > 0) {
                        console.log(chalk.red(`\nWorkflow(s) not found in source: ${missing.join(', ')}`));
                        console.log(chalk.gray(`Available: ${[...discoveredNames].join(', ')}`));
                        process.exit(1);
                    }
                    discovered = discovered.filter((w) => requestedNames.includes(w.name));
                }
                console.log(chalk.bold(`\nFound ${discovered.length} workflow(s):`));
                for (const w of discovered) {
                    console.log(`\n  ${chalk.cyan(w.name)}: ${w.frontmatter.description || 'no description'}`);
                    if (w.subagentCount > 0) {
                        console.log(`    ${chalk.gray(`${w.subagentCount} subagent${w.subagentCount === 1 ? '' : 's'}`)}`);
                    }
                }
                const installSpinner = ora('Installing to central storage...').start();
                let installed = 0;
                for (const w of discovered) {
                    const result = installWorkflowCentrally(w.path, w.name);
                    if (result.success) {
                        installed++;
                    }
                    else {
                        installSpinner.stop();
                        console.log(chalk.red(`\n  Failed to install ${w.name}: ${result.error}`));
                        installSpinner.start();
                    }
                }
                installSpinner.succeed(`Installed ${installed} workflow(s) to ~/.agents/workflows/`);
                workflows = discovered.map(w => ({
                    name: w.name,
                    path: path.join(getUserWorkflowsDir(), w.name),
                }));
            }
            // Agent/version selection
            let selectedAgents;
            let versionSelections;
            if (options.agents) {
                const result = await resolveAgentTargetsAutoInstalling(options.agents, capableAgents('workflows'), { yes: options.yes });
                if (!result) {
                    console.log(chalk.gray('Cancelled.'));
                    return;
                }
                selectedAgents = result.selectedAgents;
                versionSelections = result.versionSelections;
            }
            else {
                const result = await promptAgentVersionSelection(capableAgents('workflows'), {
                    skipPrompts: options.yes,
                });
                selectedAgents = result.selectedAgents;
                versionSelections = result.versionSelections;
            }
            if (selectedAgents.length === 0) {
                console.log(chalk.yellow('\nNo agents selected.'));
                return;
            }
            const syncSpinner = ora('Syncing to agent versions...').start();
            let synced = 0;
            const workflowNames = workflows.map(w => w.name);
            for (const [agentId, versions] of versionSelections) {
                for (const version of versions) {
                    syncResourcesToVersion(agentId, version);
                    recordVersionResources(agentId, version, 'workflows', workflowNames);
                    synced++;
                }
            }
            if (synced > 0) {
                syncSpinner.succeed(`Synced to ${synced} agent version(s)`);
            }
            else {
                syncSpinner.info('No version-managed agents to sync');
            }
            console.log(chalk.green('\nWorkflows installed.'));
            console.log(chalk.gray('Run with: agents run <workflow-name>'));
        }
        catch (err) {
            if (isPromptCancelled(err)) {
                console.log(chalk.gray('\nCancelled'));
                return;
            }
            console.error(chalk.red('Failed to add workflows'));
            console.error(chalk.red(err.message));
            process.exit(1);
        }
    });
    withAliases(workflowsCmd
        .command('remove [name]'), 'remove')
        .description('Remove a workflow from version homes (interactive picker if no name given)')
        .addHelpText('after', `
Examples:
  # Remove a workflow by name
  agents workflows remove rdev

  # Interactive picker
  agents workflows remove
`)
        .action(async (name) => {
        const workflowTargetMap = new Map();
        for (const { agent, version } of iterWorkflowsCapableVersions()) {
            const home = getVersionHomePath(agent, version);
            for (const n of listWorkflowsForAgent(agent, home)) {
                const existing = workflowTargetMap.get(n);
                if (existing) {
                    existing.targets.push({ agent, version });
                }
                else {
                    workflowTargetMap.set(n, { name: n, targets: [{ agent, version }] });
                }
            }
        }
        let toRemove;
        if (name) {
            toRemove = [name];
        }
        else {
            if (workflowTargetMap.size === 0) {
                console.log(chalk.yellow('No workflows synced to any version.'));
                return;
            }
            if (!isInteractiveTerminal()) {
                requireInteractiveSelection('Selecting workflows to remove', [
                    'agents workflows remove rdev',
                ]);
            }
            try {
                const selected = await checkbox({
                    message: 'Select workflows to remove',
                    choices: Array.from(workflowTargetMap.values()).map(w => ({
                        value: w.name,
                        name: w.name,
                    })),
                });
                if (selected.length === 0) {
                    console.log(chalk.gray('No workflows selected.'));
                    return;
                }
                toRemove = selected;
            }
            catch (err) {
                if (isPromptCancelled(err)) {
                    console.log(chalk.gray('Cancelled'));
                    return;
                }
                throw err;
            }
        }
        let removed = 0;
        for (const workflowName of toRemove) {
            const info = workflowTargetMap.get(workflowName);
            if (!info || info.targets.length === 0) {
                // Not synced to any version — try removing from central storage directly
                const result = removeWorkflow(workflowName);
                if (result.success) {
                    console.log(`  ${chalk.red('-')} ${workflowName}: removed from central storage`);
                    removed++;
                }
                else {
                    console.log(chalk.yellow(`  Workflow '${workflowName}' not found.`));
                }
                continue;
            }
            const removalTargets = info.targets.map(t => ({
                agent: t.agent,
                version: t.version,
                label: `${agentLabel(t.agent)}@${t.version}`,
            }));
            const selectedTargets = await promptRemovalTargets(workflowName, removalTargets);
            if (selectedTargets.length === 0) {
                console.log(chalk.gray(`  Skipped '${workflowName}'.`));
                continue;
            }
            for (const target of selectedTargets) {
                const result = removeWorkflowFromVersion(target.agent, target.version, workflowName);
                if (result.success) {
                    console.log(`  ${chalk.red('-')} ${target.label}: ${workflowName}`);
                    removed++;
                }
                else if (result.error) {
                    console.log(`  ${chalk.yellow('!')} ${target.label}: ${result.error}`);
                }
            }
        }
        if (removed === 0) {
            console.log(chalk.yellow('No workflows removed.'));
        }
        else {
            console.log(chalk.green(`\nRemoved ${removed} workflow(s) from version homes.`));
            console.log(chalk.gray('Central source unchanged. Use "agents workflows remove <name>" again to remove from ~/.agents/workflows/.'));
        }
    });
    withAliases(workflowsCmd
        .command('view [name]'), 'view')
        .description('Read workflow details (description, subagents, model, MCP)')
        .addHelpText('after', `
Examples:
  # View a specific workflow
  agents workflows view rdev

  # Interactive picker
  agents workflows view
`)
        .action(async (name) => {
        const installed = listInstalledWorkflows();
        if (!name) {
            if (installed.size === 0) {
                console.log(chalk.yellow('No workflows installed'));
                return;
            }
            if (!isInteractiveTerminal()) {
                requireInteractiveSelection('Selecting a workflow to view', [
                    'agents workflows view rdev',
                ]);
            }
            try {
                name = await select({
                    message: 'Select a workflow to view',
                    choices: Array.from(installed.values()).map(w => ({
                        value: w.name,
                        name: w.frontmatter.description
                            ? `${w.name} - ${w.frontmatter.description}`
                            : w.name,
                    })),
                });
            }
            catch (err) {
                if (isPromptCancelled(err)) {
                    console.log(chalk.gray('Cancelled'));
                    return;
                }
                throw err;
            }
        }
        const workflow = installed.get(name);
        if (!workflow) {
            console.log(chalk.yellow(`Workflow '${name}' not found`));
            return;
        }
        const lines = [];
        const fm = workflow.frontmatter;
        lines.push(chalk.bold(`\n${fm.name || workflow.name}\n`));
        if (fm.description)
            lines.push(`  ${fm.description}`);
        lines.push('');
        if (fm.model)
            lines.push(`  Model:   ${fm.model}`);
        if (fm.tools?.length)
            lines.push(`  Tools:   ${fm.tools.join(', ')}`);
        if (fm.mcpServers?.length)
            lines.push(`  MCP:     ${fm.mcpServers.join(', ')}`);
        if (fm.skills?.length)
            lines.push(`  Skills:  ${fm.skills.join(', ')}`);
        if (fm.secrets?.length)
            lines.push(`  Secrets: ${fm.secrets.join(', ')}  ${chalk.gray('(auto-injected at run time — pass --no-auto-secrets to skip)')}`);
        lines.push(`  Path:    ${workflow.path}`);
        if (fm.allowedAgents?.length) {
            lines.push(chalk.bold(`\n  Subagents (${workflow.subagentCount}):`));
            for (const a of fm.allowedAgents) {
                lines.push(`    ${chalk.cyan(a)}`);
            }
        }
        lines.push('');
        printWithPager(lines.join('\n'), lines.length);
    });
}
function buildWorkflowRows(opts) {
    const central = listInstalledWorkflows();
    if (central.size === 0)
        return [];
    const targetPairs = iterWorkflowsCapableVersions({
        agent: opts.filterAgent,
        version: opts.filterVersion,
    });
    const syncedByTarget = new Map();
    const defaultByAgent = new Map();
    for (const { agent, version } of targetPairs) {
        if (!defaultByAgent.has(agent))
            defaultByAgent.set(agent, getGlobalDefault(agent));
        const home = getVersionHomePath(agent, version);
        syncedByTarget.set(`${agent}@${version}`, new Set(listWorkflowsForAgent(agent, home)));
    }
    const rows = [];
    for (const [name, workflow] of central) {
        const targets = targetPairs.map(({ agent, version }) => ({
            agent,
            version,
            isDefault: defaultByAgent.get(agent) === version,
            status: syncedByTarget.get(`${agent}@${version}`)?.has(name) ? 'synced' : 'missing',
        }));
        rows.push({
            name,
            description: workflow.frontmatter.description,
            extra: workflow.subagentCount > 0 ? `${workflow.subagentCount}` : '-',
            targets,
            buildDetail: () => formatWorkflowDetail(workflow, targets),
        });
    }
    rows.sort((a, b) => {
        const aSynced = a.targets.filter(t => t.status === 'synced').length;
        const bSynced = b.targets.filter(t => t.status === 'synced').length;
        if (aSynced !== bSynced)
            return bSynced - aSynced;
        return a.name.localeCompare(b.name);
    });
    return rows;
}
function formatWorkflowDetail(workflow, targets) {
    const lines = [];
    const fm = workflow.frontmatter;
    lines.push(chalk.bold.cyan(workflow.name));
    if (fm.description)
        lines.push(chalk.gray(fm.description));
    lines.push('');
    const meta = [];
    if (fm.model)
        meta.push(`model ${chalk.white(fm.model)}`);
    if (fm.mcpServers?.length)
        meta.push(`${chalk.white(fm.mcpServers.length)} MCP`);
    if (fm.skills?.length)
        meta.push(`${chalk.white(fm.skills.length)} skill${fm.skills.length === 1 ? '' : 's'}`);
    meta.push(`${chalk.white(workflow.subagentCount)} subagent${workflow.subagentCount === 1 ? '' : 's'}`);
    if (meta.length)
        lines.push('  ' + meta.join(chalk.gray(' · ')));
    lines.push('  ' + chalk.gray(workflow.path));
    lines.push('');
    lines.push(chalk.bold('  Synced to'));
    lines.push(buildTargetsSection(targets));
    return lines.join('\n');
}
