import { resolve } from 'node:path';
import { buildCommandContext } from '../../app/command-context.js';
import { readGlobalOptions } from '../shared/shared.utils.js';
import { resolveAssetsRoot } from '../../fs/assets.js';
import { resolveProjectRoot } from '../../fs/paths.js';
import { Command } from 'commander';
import { initializeDecisionRecords } from './init.js';
import { migrateDecisionRecords } from './migrate.js';
import { createDecisionRecord } from './new.js';
import { regenerateDecisionIndex } from './regenerate-index.js';
const DEFAULT_DEPENDENCIES = {
    buildCommandContext,
    resolveProjectRoot,
    resolveAssetsRoot,
    initializeDecisionRecords,
    regenerateDecisionIndex,
    createDecisionRecord,
    migrateDecisionRecords,
};
async function resolveDecisionsRoot(context, projectRoot, configuredRoot) {
    if (configuredRoot) {
        return resolve(context.cwd, configuredRoot);
    }
    return resolve(projectRoot, '.oat', 'repo', 'reference', 'decisions');
}
async function resolveReferenceRoot(context, projectRoot, configuredRoot) {
    if (configuredRoot) {
        return resolve(context.cwd, configuredRoot);
    }
    return resolve(projectRoot, '.oat', 'repo', 'reference');
}
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;
}
export function createDecisionCommand(overrides = {}) {
    const dependencies = {
        ...DEFAULT_DEPENDENCIES,
        ...overrides,
    };
    const cmd = new Command('decision').description('Manage file-backed decision records and indexes');
    cmd
        .command('init')
        .description('Scaffold the canonical decision directory and index')
        .option('--decisions-root <path>', 'Decisions root directory (defaults to .oat/repo/reference/decisions)')
        .action(async (options, command) => {
        const context = dependencies.buildCommandContext(readGlobalOptions(command));
        try {
            const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
            const decisionsRoot = await resolveDecisionsRoot(context, projectRoot, options.decisionsRoot);
            const result = await dependencies.initializeDecisionRecords(decisionsRoot);
            if (context.json) {
                context.logger.json({ status: 'ok', ...result });
            }
            else {
                context.logger.info(`Initialized decision scaffold at ${result.decisionsRoot}`);
                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(', ')}`);
                }
            }
            process.exitCode = 0;
        }
        catch (error) {
            reportError(context, error);
        }
    });
    cmd
        .command('regenerate-index')
        .description('Regenerate the managed decision index table')
        .option('--decisions-root <path>', 'Decisions root directory (defaults to .oat/repo/reference/decisions)')
        .action(async (options, command) => {
        const context = dependencies.buildCommandContext(readGlobalOptions(command));
        try {
            const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
            const decisionsRoot = await resolveDecisionsRoot(context, projectRoot, options.decisionsRoot);
            await dependencies.regenerateDecisionIndex(decisionsRoot);
            if (context.json) {
                context.logger.json({ status: 'ok', decisionsRoot });
            }
            else {
                context.logger.info(`Regenerated decision index at ${decisionsRoot}`);
            }
            process.exitCode = 0;
        }
        catch (error) {
            reportError(context, error);
        }
    });
    cmd
        .command('new')
        .description('Create a new file-backed decision record')
        .argument('<title>', 'Decision title')
        .option('--decisions-root <path>', 'Decisions root directory (defaults to .oat/repo/reference/decisions)')
        .option('--status <status>', 'Decision status', 'proposed')
        .option('--context <text>', 'Initial context body text')
        .option('--decision <text>', 'Initial decision body text')
        .option('--consequences <text>', 'Initial consequences body text')
        .option('--created-at <timestamp>', 'Creation timestamp seed for reproducible ID generation')
        .action(async (title, options, command) => {
        const context = dependencies.buildCommandContext(readGlobalOptions(command));
        try {
            const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
            const decisionsRoot = await resolveDecisionsRoot(context, projectRoot, options.decisionsRoot);
            const assetsRoot = await dependencies.resolveAssetsRoot();
            const result = await dependencies.createDecisionRecord({
                decisionsRoot,
                assetsRoot,
                templatesRoot: resolve(projectRoot, '.oat', 'templates'),
                title,
                status: options.status,
                context: options.context,
                decision: options.decision,
                consequences: options.consequences,
                createdAt: options.createdAt,
            });
            if (context.json) {
                context.logger.json({ status: 'ok', ...result });
            }
            else {
                context.logger.info(`Created decision record ${result.id}`);
                context.logger.info(`Wrote ${result.filePath}`);
            }
            process.exitCode = 0;
        }
        catch (error) {
            reportError(context, error);
        }
    });
    cmd
        .command('migrate')
        .description('Migrate legacy decision-record.md into decision records')
        .option('--reference-root <path>', 'Reference root directory (defaults to .oat/repo/reference)')
        .option('--dry-run', 'Print legacy-to-new mappings without writing files')
        .option('--delete-legacy', 'Delete decision-record.md after a verified migration')
        .action(async (options, command) => {
        const context = dependencies.buildCommandContext(readGlobalOptions(command));
        try {
            const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
            const referenceRoot = await resolveReferenceRoot(context, projectRoot, options.referenceRoot);
            const result = await dependencies.migrateDecisionRecords({
                referenceRoot,
                dryRun: options.dryRun ?? false,
                deleteLegacy: options.deleteLegacy ?? false,
            });
            if (context.json) {
                context.logger.json({ status: 'ok', ...result });
            }
            else if (!result.legacyPresent) {
                // Absent-file no-op (F4): a prior `pjm migrate` already migrated and
                // removed decision-record.md. Report a friendly no-op, not a throw.
                context.logger.info(result.message ??
                    'Nothing to migrate; no legacy decision-record.md found.');
            }
            else {
                context.logger.info(result.dryRun
                    ? `Decision migration dry run for ${result.referenceRoot}`
                    : `Migrated decisions into ${result.decisionsRoot}`);
                for (const mapping of result.mappings) {
                    context.logger.info(`${mapping.legacyId} -> ${mapping.id} (${mapping.filePath})`);
                }
                if (result.deletedLegacy) {
                    context.logger.info('Deleted legacy decision-record.md');
                }
            }
            process.exitCode = 0;
        }
        catch (error) {
            reportError(context, error);
        }
    });
    return cmd;
}
