#!/usr/bin/env node
// Copyright (c) 2026 Hellmai Ltd
// SPDX-License-Identifier: AGPL-3.0-only
import { existsSync, readFileSync, writeFileSync, renameSync, readdirSync } from 'node:fs';
import path, { join } from 'node:path';
import { createWUParser, WU_OPTIONS } from '@lumenflow/core/arg-parser';
import { getConfig } from '@lumenflow/core/config';
import { canonicalizeInitiativeId, initiativeIdRegex, loadInitiativeIdConfig, } from '@lumenflow/core';
import { die } from '@lumenflow/core/error-handler';
import { parseYAML, stringifyYAML } from '@lumenflow/core/wu-yaml';
import { ensureOnMain } from '@lumenflow/core/wu-helpers';
import { getGitForCwd } from '@lumenflow/core/git-adapter';
import { withMicroWorktree } from '@lumenflow/core/micro-worktree';
import { runCLI } from './cli-entry-point.js';
const PREFIX = '[initiative:rename]';
const OPERATION = 'initiative-rename';
function readYamlObject(filePath) {
    const raw = readFileSync(filePath, 'utf-8');
    const parsed = parseYAML(raw);
    if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
        throw new Error(`${PREFIX} Invalid YAML object: ${filePath}`);
    }
    return parsed;
}
function resolveConfiguredDir(worktreePath, configuredRelativePath, fallbackRelativePath) {
    const configuredAbsolute = join(worktreePath, configuredRelativePath);
    if (existsSync(configuredAbsolute)) {
        return configuredRelativePath;
    }
    const fallbackAbsolute = join(worktreePath, fallbackRelativePath);
    if (existsSync(fallbackAbsolute)) {
        return fallbackRelativePath;
    }
    return configuredRelativePath;
}
function resolveInitiativePaths(worktreePath, id) {
    const initiativesDir = resolveConfiguredDir(worktreePath, getConfig({ projectRoot: worktreePath }).directories.initiativesDir, 'docs/operations/tasks/initiatives');
    return {
        initiativesDir,
        filePath: join(worktreePath, initiativesDir, `${id}.yaml`),
    };
}
function canonicalizeInitiativeLifecycleId(id, projectRoot) {
    const config = loadInitiativeIdConfig({ projectRoot });
    const canonical = canonicalizeInitiativeId(id, config);
    if (canonical) {
        return canonical;
    }
    if (initiativeIdRegex(config).test(id)) {
        return id;
    }
    throw new Error(`${PREFIX} Invalid initiative ID: ${id}`);
}
function updateLinkedWuInitiativeRefs(worktreePath, from, to) {
    const wuDir = join(worktreePath, resolveConfiguredDir(worktreePath, getConfig({ projectRoot: worktreePath }).directories.wuDir, 'docs/operations/tasks/wu'));
    if (!existsSync(wuDir)) {
        return [];
    }
    const touched = [];
    for (const fileName of readdirSync(wuDir)) {
        if (!fileName.endsWith('.yaml')) {
            continue;
        }
        const filePath = path.join(wuDir, fileName);
        const doc = readYamlObject(filePath);
        if (doc.initiative !== from) {
            continue;
        }
        doc.initiative = to;
        writeFileSync(filePath, stringifyYAML(doc), 'utf-8');
        touched.push(filePath);
    }
    return touched;
}
export async function performInitiativeRenameTransaction(input) {
    const fromPaths = resolveInitiativePaths(input.worktreePath, input.from);
    const toPaths = resolveInitiativePaths(input.worktreePath, input.to);
    if (!existsSync(fromPaths.filePath)) {
        throw new Error(`${PREFIX} Source initiative not found: ${input.from}`);
    }
    if (existsSync(toPaths.filePath)) {
        throw new Error(`${PREFIX} Target initiative already exists: ${input.to}`);
    }
    const doc = readYamlObject(fromPaths.filePath);
    if (doc.id !== input.from) {
        throw new Error(`${PREFIX} Initiative YAML id mismatch. Expected ${input.from}, found ${String(doc.id)}`);
    }
    renameSync(fromPaths.filePath, toPaths.filePath);
    doc.id = input.to;
    if (typeof doc.related_plan === 'string') {
        doc.related_plan = doc.related_plan.replaceAll(input.from, input.to);
    }
    writeFileSync(toPaths.filePath, stringifyYAML(doc), 'utf-8');
    const wuFiles = updateLinkedWuInitiativeRefs(input.worktreePath, input.from, input.to);
    return {
        filesTouched: [fromPaths.filePath, toPaths.filePath, ...wuFiles],
    };
}
async function ensureCleanWorkingTree() {
    const status = await getGitForCwd().getStatus();
    if (status.trim()) {
        die(`Working tree is not clean. Cannot rename initiative.\n\nUncommitted changes:\n${status}\n`);
    }
}
export async function main() {
    const args = createWUParser({
        name: 'initiative-rename',
        description: 'Rename an initiative and rewrite linked WU references',
        options: [WU_OPTIONS.from, WU_OPTIONS.to],
        required: ['from', 'to'],
    });
    const projectRoot = process.cwd();
    const from = canonicalizeInitiativeLifecycleId(args.from, projectRoot);
    const to = canonicalizeInitiativeLifecycleId(args.to, projectRoot);
    if (from === to) {
        die(`${PREFIX} --from and --to must differ`);
    }
    await ensureOnMain(getGitForCwd());
    await ensureCleanWorkingTree();
    await withMicroWorktree({
        operation: OPERATION,
        id: from,
        logPrefix: PREFIX,
        pushOnly: true,
        execute: async ({ worktreePath }) => {
            const result = await performInitiativeRenameTransaction({ worktreePath, from, to });
            return {
                commitMessage: `docs: rename ${from.toLowerCase()} to ${to.toLowerCase()}`,
                files: result.filesTouched.map((filePath) => path.relative(worktreePath, filePath)),
            };
        },
    });
    console.log(`${PREFIX} Renamed ${from} -> ${to}`);
}
if (import.meta.main) {
    void runCLI(main);
}
//# sourceMappingURL=initiative-rename.js.map