import { readFile, writeFile } from 'node:fs/promises';
import { isAbsolute, join, resolve } from 'node:path';
import { buildCommandContext, } from '../../../app/command-context.js';
import { readGlobalOptions } from '../../shared/shared.utils.js';
import { resolveActiveProject, } from '../../../config/oat-config.js';
import { dirExists, fileExists } from '../../../fs/io.js';
import { resolveProjectRoot } from '../../../fs/paths.js';
import { Command } from 'commander';
import { findCanonicalProjectLogSynthesisSection, PROJECT_LOG_FILENAME, SYNTHESIS_COMPLETE_HEADING, SYNTHESIS_PENDING_HEADING, } from './check.js';
const DEFAULT_SYNTHESIZE_DEPENDENCIES = {
    resolveActiveProject,
};
const DEFAULT_COMMAND_DEPENDENCIES = {
    ...DEFAULT_SYNTHESIZE_DEPENDENCIES,
    buildCommandContext,
    resolveProjectRoot,
    readStdin: async () => {
        const chunks = [];
        for await (const chunk of process.stdin) {
            chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
        }
        return Buffer.concat(chunks).toString('utf8');
    },
};
async function resolveTargetProject(input, dependencies) {
    if (input.project) {
        const projectPath = isAbsolute(input.project)
            ? resolve(input.project)
            : resolve(input.repoRoot, input.project);
        if (!(await dirExists(projectPath)) ||
            !(await fileExists(join(projectPath, 'state.md')))) {
            throw new Error(`Project path is missing or invalid: ${input.project}. Pass --project <path> for a directory containing state.md.`);
        }
        return projectPath;
    }
    const active = await dependencies.resolveActiveProject(input.repoRoot);
    if (active.status !== 'active' || !active.path) {
        throw new Error('No active project resolves. Set activeProject or pass --project <path>.');
    }
    return resolve(input.repoRoot, active.path);
}
export async function synthesizeProjectLog(input, overrides = {}) {
    const dependencies = {
        ...DEFAULT_SYNTHESIZE_DEPENDENCIES,
        ...overrides,
    };
    const body = input.body?.trim();
    if (!body) {
        throw new Error('--body is required and must contain non-whitespace text.');
    }
    if (body
        .split(/\r?\n/)
        .some((line) => line === SYNTHESIS_PENDING_HEADING ||
        line === SYNTHESIS_COMPLETE_HEADING)) {
        throw new Error('--body must not recreate command-owned project-log synthesis markers.');
    }
    const projectPath = await resolveTargetProject(input, dependencies);
    const logPath = join(projectPath, PROJECT_LOG_FILENAME);
    if (!(await fileExists(logPath))) {
        throw new Error(`Project log does not exist: ${logPath}. Append an entry before synthesizing.`);
    }
    const content = await readFile(logPath, 'utf8');
    const synthesis = findCanonicalProjectLogSynthesisSection(content);
    if (synthesis.status === 'complete') {
        throw new Error('End-of-run synthesis is already written; append a correction judgment instead of replacing it.');
    }
    if (synthesis.status === 'ambiguous') {
        throw new Error('Project log must contain one unique canonical end-of-run synthesis section and cannot be synthesized safely.');
    }
    if (synthesis.status === 'missing') {
        throw new Error('Project log is missing the pending synthesis marker and cannot be synthesized safely.');
    }
    const suffix = content.slice(synthesis.section.end);
    const nextContent = `${content.slice(0, synthesis.section.start)}${SYNTHESIS_COMPLETE_HEADING}\n\n${body}\n${suffix ? '\n' : ''}${suffix}`;
    await writeFile(logPath, nextContent, 'utf8');
    return { status: 'synthesized', logPath };
}
async function runSynthesizeCommand(options, context, dependencies) {
    try {
        const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
        const body = options.body === '-' ? await dependencies.readStdin() : options.body;
        const result = await synthesizeProjectLog({ repoRoot, project: options.project, body }, dependencies);
        if (context.json) {
            context.logger.json(result);
        }
        else {
            context.logger.success(`Wrote project log synthesis: ${result.logPath}`);
        }
        process.exitCode = 0;
    }
    catch (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 createProjectLogSynthesizeCommand(overrides = {}) {
    const dependencies = { ...DEFAULT_COMMAND_DEPENDENCIES, ...overrides };
    return new Command('synthesize')
        .description('Complete the project log end-of-run synthesis')
        .option('--body <text>', 'Synthesis body, or - to read from stdin')
        .option('--project <path>', 'Explicit project path; defaults to the active project')
        .action(async (options, command) => {
        const context = dependencies.buildCommandContext(readGlobalOptions(command));
        await runSynthesizeCommand(options, context, dependencies);
    });
}
