/**
 * Pure builders behind `agents projects import`.
 *
 * Currently supports one source: **Linear** (projects someone deliberately
 * created on the board). Results funnel through `writeProjectDef`.
 *
 * Everything here is a pure function of its arguments — no fs, no shell, no
 * process env. The command layer shells out to `linear` and hands the rows in;
 * that's what makes these testable against plain fixtures with no mocking.
 * The one exception is `toHomeRelative`, a string rewrite against `$HOME`.
 */
import { isSafeProjectName } from './projects.js';
import { matchLocalCheckoutExact } from './linear-projects.js';
/**
 * Validate the flag combination, throwing a user-facing message on the first
 * problem.
 */
export function validateImportOpts(flags) {
    if (!flags.fromLinear)
        throw new Error('Pick an import source: --from-linear.');
    return { source: 'linear', force: flags.force === true };
}
/**
 * Turn a Linear project name into a definition slug: lowercase, every run of
 * unusable characters collapsed to one `-`, trimmed of leading/trailing
 * punctuation, capped at the 64 chars `isSafeProjectName` allows. Returns `''`
 * when nothing usable survives — the caller skips those loudly.
 */
export function slugifyProjectName(name) {
    const slug = name
        .toLowerCase()
        .replace(/[^a-z0-9._-]+/g, '-')
        .replace(/-{2,}/g, '-')
        .replace(/^[-._]+|[-._]+$/g, '')
        .slice(0, 64)
        .replace(/[-._]+$/g, '');
    return isSafeProjectName(slug) ? slug : '';
}
/**
 * Plan the Linear import. Every project becomes a def carrying its `linear`
 * link; the local checkout is bound **only on an exact normalized-name match**
 * (`matchLocalCheckoutExact`). The containment fallback that powers the `link`
 * suggestion is deliberately not used here — "Agents CLI" containing
 * "agents-cli-web" is a fine hint for a human to confirm, and a silently wrong
 * `root` on a write path.
 *
 * An existing def is preserved field-for-field; only `name` and `linear` are
 * overwritten, so a hand-set `description`/`contexts`/`integrations` survives a
 * re-import.
 */
export function buildLinearImportCandidates(projects, existing, deps, opts) {
    const defs = [];
    const skipped = [];
    const seen = new Set();
    for (const p of projects) {
        const name = slugifyProjectName(p.name);
        if (!name) {
            skipped.push({ name: p.name, reason: 'no usable project name (letters, digits, ., _, - only)' });
            continue;
        }
        if (seen.has(name)) {
            skipped.push({ name: p.name, reason: `another Linear project already claimed the name "${name}"` });
            continue;
        }
        const prior = existing.get(name);
        if (prior && (prior.root || prior.repo) && !opts.force) {
            skipped.push({ name, reason: 'existing def already has root/repo — pass --force to relink' });
            continue;
        }
        seen.add(name);
        // The Linear display name is recorded verbatim (`p.name`), not the
        // slugified def name: `agi` is the local id, "AGI" is what the board calls
        // it, and agents read the latter when they name the project.
        const def = { ...prior, name, linear: { projectId: p.id, name: p.name } };
        if (p.url)
            def.linear.url = p.url;
        const dir = matchLocalCheckoutExact(p.name, deps.localDirs);
        if (dir) {
            const root = deps.resolveRoot(dir);
            if (root)
                def.root = root;
            const repo = deps.resolveOrigin(dir);
            if (repo)
                def.repo = repo;
        }
        defs.push(def);
    }
    return { defs, skipped };
}
