/**
 * olam workspace — manage the named catalog of repo bundles that
 * worlds instantiate from.
 *
 *   olam workspace list                                 list all workspaces
 *   olam workspace add <name> [--from-config]           create from repeated --repo flags
 *                             [--repo url[:branch]]...  or from the current project's
 *                             [--default-branch <b>]    .olam/config.yaml
 *                             [--force]
 *   olam workspace show <name>                          pretty-print YAML
 *   olam workspace remove <name> [--force]              delete a workspace
 *
 * Data at `~/.olam/workspaces/<name>.yaml`. Schema is the CF
 * `Workspace` shape + `updatedAt` — see packages/core/src/workspace.
 */
import * as fs from 'node:fs';
import * as path from 'node:path';
import pc from 'picocolors';
import { stringify as stringifyYaml } from 'yaml';
import { listWorkspaces, readWorkspace, removeWorkspace, workspacesDir, writeWorkspace, WorkspaceExistsError, WorkspaceNameError, } from '@olam/core/src/workspace/index.js';
import { loadConfig } from '@olam/core/src/config/loader.js';
import { printError, printHeader, printInfo, printSuccess } from '../output.js';
function printWorkspaceNotFound(name) {
    printError(`No workspace named "${name}" under ${workspacesDir()}`);
}
/**
 * Parse `url` or `url#branch`. Using `#` (not `:`) as the branch
 * separator because URLs legitimately contain `:` (`https://host:port/...`,
 * `git@host:user/repo`) which makes `url:branch` ambiguous. `#` never
 * appears in a repo URL, so this split is unambiguous.
 */
function parseRepoFlag(raw) {
    const hashIdx = raw.indexOf('#');
    const url = hashIdx === -1 ? raw : raw.slice(0, hashIdx);
    const branch = hashIdx === -1 ? undefined : raw.slice(hashIdx + 1);
    if (url.length === 0)
        throw new Error(`invalid --repo value "${raw}" (empty url)`);
    if (branch !== undefined && branch.length === 0) {
        throw new Error(`invalid --repo value "${raw}" (empty branch after #)`);
    }
    const nameFromUrl = url
        .replace(/\.git$/, '')
        .split(/[\/:]/)
        .filter(Boolean)
        .at(-1) ?? 'repo';
    return branch ? { name: nameFromUrl, url, branch } : { name: nameFromUrl, url };
}
export function registerWorkspace(program) {
    const workspace = program
        .command('workspace')
        .description('Manage the named catalog of repo bundles that worlds instantiate from');
    workspace
        .command('list')
        .description('List all workspaces (name, repoCount, updatedAt)')
        .action(() => {
        const all = listWorkspaces();
        if (all.length === 0) {
            console.log(pc.dim(`No workspaces under ${workspacesDir()}`));
            return;
        }
        printHeader(`${all.length} workspace(s)`);
        for (const ws of all) {
            const when = new Date(ws.updatedAt).toISOString().slice(0, 10);
            console.log(`  ${pc.bold(ws.name.padEnd(24))} ${String(ws.repos.length).padEnd(3)} repos   ${pc.dim(when)}`);
        }
    });
    workspace
        .command('show')
        .description('Show a workspace as YAML')
        .argument('<name>', 'Workspace name')
        .action((name) => {
        try {
            const ws = readWorkspace(name);
            if (!ws) {
                printWorkspaceNotFound(name);
                process.exitCode = 1;
                return;
            }
            process.stdout.write(stringifyYaml(ws));
        }
        catch (err) {
            printError(err instanceof Error ? err.message : String(err));
            process.exitCode = 1;
        }
    });
    workspace
        .command('remove')
        .description('Delete a workspace (does NOT touch worlds that already referenced it)')
        .argument('<name>', 'Workspace name')
        .option('--force', 'Skip confirmation', false)
        .action((name, _opts) => {
        try {
            if (removeWorkspace(name)) {
                printSuccess(`Removed workspace "${name}"`);
            }
            else {
                printWorkspaceNotFound(name);
                process.exitCode = 1;
            }
        }
        catch (err) {
            printError(err instanceof Error ? err.message : String(err));
            process.exitCode = 1;
        }
    });
    workspace
        .command('add')
        .description('Create a workspace from --from-config (reads current .olam/config.yaml) or repeated --repo flags')
        .argument('<name>', 'Workspace name')
        .option('--from-config', 'Seed from the repos in the current project\'s .olam/config.yaml', false)
        .option('--repo <url>', 'Repeatable. Format: <url> or <url>#<branch>', (val, acc) => {
        acc.push(parseRepoFlag(val));
        return acc;
    }, [])
        .option('--default-branch <branch>', 'Fallback branch for repos that don\'t specify one')
        .option('--force', 'Overwrite an existing workspace with the same name', false)
        .action((name, opts) => {
        try {
            const repos = [...opts.repo];
            if (opts.fromConfig) {
                try {
                    const cfg = loadConfig(process.cwd());
                    for (const r of cfg.repos) {
                        repos.push({
                            name: r.name,
                            url: r.url,
                            ...(r.submodules ? { submodules: true } : {}),
                        });
                    }
                }
                catch (err) {
                    printError(`--from-config: ${err instanceof Error ? err.message : String(err)}`);
                    process.exitCode = 1;
                    return;
                }
            }
            if (repos.length === 0) {
                printError('No repos provided — pass --from-config or at least one --repo');
                process.exitCode = 1;
                return;
            }
            const ws = {
                name,
                repos,
                ...(opts.defaultBranch ? { defaults: { branch: opts.defaultBranch } } : {}),
                updatedAt: Date.now(),
            };
            writeWorkspace(ws, { force: opts.force });
            const file = path.join(workspacesDir(), `${name}.yaml`);
            printSuccess(`Created workspace "${name}" (${repos.length} repo${repos.length === 1 ? '' : 's'})`);
            printInfo('File', file);
            printInfo('Next', `olam create --name <world> --workspace ${name} --task "..."`);
        }
        catch (err) {
            if (err instanceof WorkspaceExistsError || err instanceof WorkspaceNameError) {
                printError(err.message);
                process.exitCode = 1;
                return;
            }
            printError(err instanceof Error ? err.message : String(err));
            process.exitCode = 1;
        }
    });
}
/** Ensure a project-scoped workspace exists, called from `olam init`. */
export function ensureProjectWorkspaceFromConfig(projectRoot, workspaceName) {
    const existing = (() => {
        try {
            return readWorkspace(workspaceName);
        }
        catch {
            return null;
        }
    })();
    if (existing) {
        return { created: false, file: path.join(workspacesDir(), `${workspaceName}.yaml`) };
    }
    // Derive repos from config.yaml at projectRoot — tolerant of read
    // failure so init still works when config.yaml is minimal.
    const cfg = loadConfig(projectRoot);
    const repos = cfg.repos.map((r) => ({
        name: r.name,
        url: r.url,
        ...(r.submodules ? { submodules: true } : {}),
    }));
    const ws = {
        name: workspaceName,
        repos,
        updatedAt: Date.now(),
    };
    writeWorkspace(ws);
    const file = path.join(workspacesDir(), `${workspaceName}.yaml`);
    return { created: true, file };
}
// Silence "fs imported but unused" when caller builds a tree without
// touching fs directly.
void fs;
//# sourceMappingURL=workspace.js.map