import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
import { dirname, join } from 'node:path';
import { initializeBacklog } from '../backlog/init.js';
import { initializeDecisionRecords } from '../decision/init.js';
import { stripTemplateFrontmatter } from '../shared/strip-template-frontmatter.js';
const TEMPLATE_TARGETS = [
    { template: 'repo-agents.md', target: 'AGENTS.md' },
    { template: 'pjm-agents.md', target: 'pjm/AGENTS.md' },
    { template: 'current-state.md', target: 'pjm/current-state.md' },
    { template: 'roadmap.md', target: 'pjm/roadmap.md' },
    { template: 'reference-agents.md', target: 'reference/AGENTS.md' },
    { template: 'repo-readme.md', target: 'README.md' },
    { template: 'pjm-handoffs-readme.md', target: 'pjm/handoffs/README.md' },
];
// Next-step hint printed after init/backfill. `oat pjm init` never writes
// CLAUDE.md shims itself — strategy ownership stays with `oat instructions
// sync`, so we point the operator at it (with the `--dry-run` preview).
export const INSTRUCTIONS_SYNC_HINT = 'Next step: run `oat instructions sync` to create CLAUDE.md shims for the ' +
    'repo-reference AGENTS.md files (preview with `oat instructions sync --dry-run`).';
const BACKLOG_PATHS = [
    'pjm/backlog/index.md',
    'pjm/backlog/completed.md',
    'pjm/backlog/items/.gitkeep',
    'pjm/backlog/archived/.gitkeep',
];
const DECISION_PATHS = ['reference/decisions/index.md'];
export const CANONICAL_REPO_REFERENCE_PATHS = [
    ...TEMPLATE_TARGETS.map((target) => target.target),
    ...BACKLOG_PATHS,
    ...DECISION_PATHS,
];
async function pathExists(path) {
    try {
        await access(path);
        return true;
    }
    catch (error) {
        const code = error && typeof error === 'object' && 'code' in error
            ? String(error.code)
            : null;
        if (code !== 'ENOENT') {
            throw error;
        }
        return false;
    }
}
async function readIfExists(path) {
    try {
        return await readFile(path, 'utf8');
    }
    catch (error) {
        const code = error && typeof error === 'object' && 'code' in error
            ? String(error.code)
            : null;
        if (code !== 'ENOENT') {
            throw error;
        }
        return null;
    }
}
async function resolveTemplateContent(name, options) {
    if (options.templatesRoot) {
        const localTemplate = await readIfExists(join(options.templatesRoot, name));
        if (localTemplate !== null) {
            return localTemplate;
        }
    }
    const bundledTemplate = await readIfExists(join(options.assetsRoot, 'templates', name));
    if (bundledTemplate !== null) {
        return bundledTemplate;
    }
    throw new Error(`Template ${name} was not found in repo-local templates or bundled assets.`);
}
async function writeFileIfMissing(filePath, content) {
    if (await pathExists(filePath)) {
        return 'skipped';
    }
    await mkdir(dirname(filePath), { recursive: true });
    await writeFile(filePath, content, 'utf8');
    return 'created';
}
export async function initializeRepoReference(options) {
    const created = [];
    const skipped = [];
    for (const target of TEMPLATE_TARGETS) {
        const targetPath = join(options.repoRoot, target.target);
        if (await pathExists(targetPath)) {
            skipped.push(target.target);
            continue;
        }
        const template = await resolveTemplateContent(target.template, options);
        const status = await writeFileIfMissing(targetPath, stripTemplateFrontmatter(template));
        if (status === 'created') {
            created.push(target.target);
        }
        else {
            skipped.push(target.target);
        }
    }
    const existingBacklogPaths = new Set();
    for (const relativePath of BACKLOG_PATHS) {
        if (await pathExists(join(options.repoRoot, relativePath))) {
            existingBacklogPaths.add(relativePath);
        }
    }
    await initializeBacklog(join(options.repoRoot, 'pjm', 'backlog'));
    for (const relativePath of BACKLOG_PATHS) {
        if (existingBacklogPaths.has(relativePath)) {
            skipped.push(relativePath);
        }
        else {
            created.push(relativePath);
        }
    }
    const existingDecisionPaths = new Set();
    for (const relativePath of DECISION_PATHS) {
        if (await pathExists(join(options.repoRoot, relativePath))) {
            existingDecisionPaths.add(relativePath);
        }
    }
    await initializeDecisionRecords(join(options.repoRoot, 'reference', 'decisions'));
    for (const relativePath of DECISION_PATHS) {
        if (existingDecisionPaths.has(relativePath)) {
            skipped.push(relativePath);
        }
        else {
            created.push(relativePath);
        }
    }
    return {
        repoRoot: options.repoRoot,
        created,
        skipped,
    };
}
