import { resolve } from 'node:path';
import { buildCommandContext } from '../../app/command-context.js';
import { readGlobalOptions } from '../shared/shared.utils.js';
import { readOatConfig } from '../../config/oat-config.js';
import { resolveAssetsRoot } from '../../fs/assets.js';
import { resolveProjectRoot } from '../../fs/paths.js';
import { formatDoctorResults } from '../../ui/output.js';
import { Command } from 'commander';
import { runPjmDoctorChecks } from './doctor.js';
import { initializeRepoReference, INSTRUCTIONS_SYNC_HINT } from './init.js';
import { migratePjmRepo, readPjmMigrationPrompt } from './migrate.js';
const DEFAULT_DEPENDENCIES = {
    buildCommandContext,
    resolveProjectRoot,
    resolveAssetsRoot,
    readOatConfig,
    initializeRepoReference,
    runPjmDoctorChecks,
    migratePjmRepo,
    readPjmMigrationPrompt,
};
async function resolveRepoRoot(context, projectRoot, configuredRoot) {
    if (configuredRoot) {
        return resolve(context.cwd, configuredRoot);
    }
    return resolve(projectRoot, '.oat', 'repo');
}
function reportError(context, error) {
    const message = error instanceof Error ? error.message : String(error);
    if (context.json) {
        context.logger.json({ status: 'error', message });
    }
    else {
        context.logger.error(message);
    }
    process.exitCode = 1;
}
function doctorStatus(checks) {
    if (checks.some((check) => check.status === 'fail')) {
        return 'fail';
    }
    if (checks.some((check) => check.status === 'warn')) {
        return 'warn';
    }
    return 'ok';
}
function setDoctorExitCode(checks) {
    const status = doctorStatus(checks);
    process.exitCode = status === 'fail' ? 2 : status === 'warn' ? 1 : 0;
}
function formatMigrationResult(result) {
    const lines = [
        `PJM migration ${result.dryRun ? 'dry run' : 'apply'} for ${result.repoRoot}`,
        `status: ${result.status}`,
    ];
    if (result.reason) {
        lines.push(`reason: ${result.reason}`);
    }
    if (result.actions.length > 0) {
        lines.push('actions:');
        for (const action of result.actions) {
            const pathSummary = action.source && action.target
                ? `${action.source} -> ${action.target}`
                : (action.source ?? action.target ?? '');
            lines.push(`- ${action.type} ${pathSummary} (${action.result}${action.reason ? `: ${action.reason}` : ''})`);
        }
    }
    if (result.backlogMappings.length > 0) {
        lines.push('backlog mappings:');
        for (const mapping of result.backlogMappings) {
            lines.push(`- ${mapping.legacyId} -> ${mapping.id}`);
        }
    }
    if (result.decisionMappings.length > 0) {
        lines.push('decision mappings:');
        for (const mapping of result.decisionMappings) {
            lines.push(`- ${mapping.legacyId} -> ${mapping.id}`);
        }
    }
    return lines.join('\n');
}
export function createPjmCommand(overrides = {}) {
    const dependencies = {
        ...DEFAULT_DEPENDENCIES,
        ...overrides,
    };
    const cmd = new Command('pjm').description('Manage project-management repo reference docs');
    cmd
        .command('init')
        .description('Scaffold the canonical PJM repo reference surface')
        .option('--repo-root <path>', 'PJM repo reference root directory (defaults to .oat/repo)')
        .action(async (options, command) => {
        const context = dependencies.buildCommandContext(readGlobalOptions(command));
        try {
            const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
            const repoRoot = await resolveRepoRoot(context, projectRoot, options.repoRoot);
            const assetsRoot = await dependencies.resolveAssetsRoot();
            const result = await dependencies.initializeRepoReference({
                repoRoot,
                assetsRoot,
                templatesRoot: resolve(projectRoot, '.oat', 'templates'),
            });
            if (context.json) {
                context.logger.json({ status: 'ok', ...result });
            }
            else {
                context.logger.info(`Initialized PJM repo reference scaffold at ${result.repoRoot}`);
                if (result.created.length > 0) {
                    context.logger.info(`Created: ${result.created.join(', ')}`);
                }
                if (result.skipped.length > 0) {
                    context.logger.info(`Skipped existing: ${result.skipped.join(', ')}`);
                }
                context.logger.info(INSTRUCTIONS_SYNC_HINT);
            }
            process.exitCode = 0;
        }
        catch (error) {
            reportError(context, error);
        }
    });
    cmd
        .command('doctor')
        .description('Run PJM repo reference diagnostics when enabled')
        .option('--repo-root <path>', 'PJM repo reference root directory (defaults to .oat/repo)')
        .action(async (options, command) => {
        const context = dependencies.buildCommandContext(readGlobalOptions(command));
        try {
            const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
            const repoRoot = await resolveRepoRoot(context, projectRoot, options.repoRoot);
            const config = await dependencies.readOatConfig(projectRoot);
            const checks = await dependencies.runPjmDoctorChecks(repoRoot, {
                projectManagementEnabled: config.tools?.['project-management'] === true,
            });
            const status = doctorStatus(checks);
            if (context.json) {
                context.logger.json({ status, repoRoot, checks });
            }
            else {
                context.logger.info(formatDoctorResults(checks));
            }
            setDoctorExitCode(checks);
        }
        catch (error) {
            reportError(context, error);
        }
    });
    cmd
        .command('migrate')
        .description('Migrate legacy PJM repo reference docs to the two-layer layout')
        .option('--repo-root <path>', 'PJM repo reference root directory (defaults to .oat/repo)')
        .option('--apply', 'Apply mechanical migration steps')
        .option('--dry-run', 'Preview migration without applying (default)')
        .option('--print-prompt', 'Print the bundled agent migration prompt')
        .action(async (options, command) => {
        const context = dependencies.buildCommandContext(readGlobalOptions(command));
        try {
            const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
            const repoRoot = await resolveRepoRoot(context, projectRoot, options.repoRoot);
            const assetsRoot = await dependencies.resolveAssetsRoot();
            if (options.printPrompt) {
                const prompt = await dependencies.readPjmMigrationPrompt(assetsRoot);
                if (context.json) {
                    context.logger.json({ status: 'ok', prompt });
                }
                else {
                    context.logger.info(prompt.trimEnd());
                }
                process.exitCode = 0;
                return;
            }
            const config = await dependencies.readOatConfig(projectRoot);
            const result = await dependencies.migratePjmRepo({
                repoRoot,
                assetsRoot,
                templatesRoot: resolve(projectRoot, '.oat', 'templates'),
                projectManagementEnabled: config.tools?.['project-management'] === true,
                apply: options.dryRun ? false : (options.apply ?? false),
            });
            if (context.json) {
                context.logger.json(result);
            }
            else {
                context.logger.info(formatMigrationResult(result));
            }
            process.exitCode = 0;
        }
        catch (error) {
            reportError(context, error);
        }
    });
    return cmd;
}
