"use strict";
// src/cli/DesignCommand.ts
// v1.15.0 — `openlife design ...` Commander subcommand group.
// Track A of the v1.15 Design.md Hub. Subcommands grow per phase:
//   - A1: pull
//   - A2: extract (added in Phase A2)
//   - A3: search, diff, drift (added in Phase A3)
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerDesignCommands = registerDesignCommands;
function emitJson(obj) {
    process.stdout.write(`${JSON.stringify(obj, null, 2)}\n`);
}
async function pullCmd(catalog, opts) {
    const { DesignMdImporter } = await Promise.resolve().then(() => __importStar(require('../design/DesignMdImporter')));
    const importer = new DesignMdImporter();
    const target = (catalog || 'core').trim();
    try {
        const metas = await importer.pullCatalog(target, {
            source: opts.source,
            richArtifacts: opts.noRich !== true,
        });
        emitJson({
            ok: true,
            catalog: target,
            imported: metas.length,
            brands: metas.map(m => ({ id: m.id, source: m.source, archetype: m.archetype, qualityScore: m.qualityScore })),
        });
    }
    catch (err) {
        emitJson({
            ok: false,
            catalog: target,
            error: err instanceof Error ? err.message : String(err),
        });
        process.exitCode = 1;
    }
}
async function listCmd(opts) {
    const { DesignMdRegistry } = await Promise.resolve().then(() => __importStar(require('../design/DesignMdRegistry')));
    const reg = new DesignMdRegistry();
    const profiles = reg.list();
    if (opts.json) {
        emitJson({ ok: true, profiles });
        return;
    }
    if (profiles.length === 0) {
        process.stdout.write('No design profiles imported yet. Try: openlife design pull\n');
        return;
    }
    process.stdout.write(`# ${profiles.length} design profile(s)\n\n`);
    for (const p of profiles) {
        const tags = [p.source, p.archetype, p.qualityScore].filter(Boolean).join(' · ');
        process.stdout.write(`  ${p.id.padEnd(25)} ${tags}\n`);
    }
}
async function extractCmd(url, opts) {
    const { DesignMdExtractor } = await Promise.resolve().then(() => __importStar(require('../design/DesignMdExtractor')));
    const extractor = new DesignMdExtractor();
    const result = await extractor.extract(url, {
        out: opts.out,
        catalog: opts.catalog,
        provider: opts.provider,
        model: opts.model,
        comparePath: opts.compare,
        noCache: opts.noCache,
        contentGate: opts.noContentGate ? false : undefined,
        timeoutMs: opts.timeoutMs,
    });
    emitJson(result);
    if (!result.ok)
        process.exitCode = 1;
}
async function searchCmd(query, opts) {
    const { DesignMdRegistry } = await Promise.resolve().then(() => __importStar(require('../design/DesignMdRegistry')));
    const reg = new DesignMdRegistry();
    const results = reg.search(query.join(' '), {
        archetype: opts.archetype,
        source: opts.source,
        qualityScore: opts.quality,
    });
    if (opts.json) {
        emitJson({ ok: true, query: query.join(' '), results });
        return;
    }
    if (results.length === 0) {
        process.stdout.write(`(no profiles match "${query.join(' ')}")\n`);
        return;
    }
    process.stdout.write(`# ${results.length} match(es) for "${query.join(' ')}"\n\n`);
    for (const r of results) {
        const tags = [r.profile.archetype, r.profile.qualityScore].filter(Boolean).join(' · ');
        process.stdout.write(`  [${r.score.toString().padStart(2)}] ${r.profile.id.padEnd(25)} ${tags}\n`);
    }
}
async function diffCmd(a, b, opts) {
    const { DesignMdRegistry } = await Promise.resolve().then(() => __importStar(require('../design/DesignMdRegistry')));
    const reg = new DesignMdRegistry();
    const result = reg.diff(a, b);
    if (!result) {
        emitJson({ ok: false, error: 'one or both profiles not found' });
        process.exitCode = 1;
        return;
    }
    if (opts.json) {
        emitJson({ ok: true, diff: result });
        return;
    }
    process.stdout.write(`# diff ${a} ↔ ${b}\n\n`);
    if (result.archetypeChanged) {
        process.stdout.write(`archetype: ${result.metaDelta.archetype.a || '—'}  →  ${result.metaDelta.archetype.b || '—'}\n`);
    }
    if (result.qualityScoreChanged) {
        process.stdout.write(`quality:   ${result.metaDelta.qualityScore.a || '—'}  →  ${result.metaDelta.qualityScore.b || '—'}\n`);
    }
    if (result.colors.length) {
        process.stdout.write(`\n## colors (${result.colors.length} delta)\n`);
        for (const c of result.colors.slice(0, 30)) {
            process.stdout.write(`  ${c.key.padEnd(30)}  ${(c.a || '—').padEnd(12)} → ${c.b || '—'}\n`);
        }
        if (result.colors.length > 30)
            process.stdout.write(`  …and ${result.colors.length - 30} more\n`);
    }
    if (result.typography.length) {
        process.stdout.write(`\n## typography (${result.typography.length} delta)\n`);
        for (const t of result.typography.slice(0, 30)) {
            process.stdout.write(`  ${t.key.padEnd(30)}  ${(t.a || '—').padEnd(20)} → ${t.b || '—'}\n`);
        }
        if (result.typography.length > 30)
            process.stdout.write(`  …and ${result.typography.length - 30} more\n`);
    }
    if (!result.colors.length && !result.typography.length && !result.archetypeChanged && !result.qualityScoreChanged) {
        process.stdout.write('(profiles are identical at meta + token level)\n');
    }
}
async function driftCmd(profile, url, opts) {
    const { DesignMdExtractor } = await Promise.resolve().then(() => __importStar(require('../design/DesignMdExtractor')));
    const { DesignMdRegistry } = await Promise.resolve().then(() => __importStar(require('../design/DesignMdRegistry')));
    const reg = new DesignMdRegistry();
    const { meta, design } = reg.get(profile);
    if (!meta || !design) {
        emitJson({ ok: false, error: `local profile not found: ${profile}` });
        process.exitCode = 1;
        return;
    }
    // Re-extract from URL into a tmp slug (no-catalog — we don't pollute design/profiles).
    const extractor = new DesignMdExtractor();
    const re = await extractor.extract(url, { catalog: false });
    if (!re.ok) {
        emitJson({ ok: false, error: 'extraction_failed', extract: re });
        process.exitCode = 1;
        return;
    }
    // Diff the local profile against the fresh extraction slug.
    const diff = reg.diff(profile, re.slug);
    if (opts.json) {
        emitJson({ ok: true, profile, url, slug: re.slug, diff });
        return;
    }
    process.stdout.write(`# drift ${profile} ↔ ${url}\n`);
    process.stdout.write(`(fresh extraction lives at ${re.outDir})\n\n`);
    if (!diff) {
        process.stdout.write('(diff unavailable — extraction did not produce tokens)\n');
        return;
    }
    const totalDeltas = diff.colors.length + diff.typography.length + (diff.archetypeChanged ? 1 : 0) + (diff.qualityScoreChanged ? 1 : 0);
    const verdict = totalDeltas === 0 ? 'in-sync ✓' : totalDeltas <= 3 ? 'minor drift' : totalDeltas <= 10 ? 'notable drift' : 'major drift ⚠';
    process.stdout.write(`verdict: ${verdict} (${totalDeltas} delta)\n`);
    if (diff.colors.length)
        process.stdout.write(`  colors:     ${diff.colors.length} changed\n`);
    if (diff.typography.length)
        process.stdout.write(`  typography: ${diff.typography.length} changed\n`);
    if (diff.archetypeChanged)
        process.stdout.write(`  archetype:  ${diff.metaDelta.archetype.a} → ${diff.metaDelta.archetype.b}\n`);
}
async function showCmd(id) {
    const { DesignMdRegistry } = await Promise.resolve().then(() => __importStar(require('../design/DesignMdRegistry')));
    const reg = new DesignMdRegistry();
    const { meta, design } = reg.get(id);
    if (!meta || !design) {
        emitJson({ ok: false, error: `profile not found: ${id}` });
        process.exitCode = 1;
        return;
    }
    // Human-readable dump with meta header followed by full DESIGN.md content.
    process.stdout.write(`# ${meta.title}\n`);
    process.stdout.write(`Source: ${meta.source}\n`);
    if (meta.archetype)
        process.stdout.write(`Archetype: ${meta.archetype}\n`);
    if (meta.qualityScore)
        process.stdout.write(`Quality: ${meta.qualityScore}\n`);
    process.stdout.write(`Imported: ${meta.importedAt}\n\n---\n\n`);
    process.stdout.write(design);
    if (!design.endsWith('\n'))
        process.stdout.write('\n');
}
function registerDesignCommands(program) {
    const d = program
        .command('design')
        .description('v1.15.0 — Design.md Hub: catalog of brand design profiles (pull / list / show / extract / search / diff / drift)');
    d.command('pull [catalog]')
        .description('Import a curated catalog of design profiles into design/profiles/. catalog ∈ {core, full, <path>}; defaults to core.')
        .option('--source <pathOrUrl>', 'Override source for `full` (local dir of 72 brands). Falls back to OPENLIFE_DESIGN_CATALOG_PATH env.')
        .option('--no-rich', 'Import only DESIGN.md, skip tokens.json/preview.html/etc.')
        .action((catalog, opts) => { void pullCmd(catalog, opts); });
    d.command('list')
        .description('List imported design profiles.')
        .option('--json', 'Emit JSON instead of human-readable.')
        .action((opts) => { void listCmd(opts); });
    d.command('show <id>')
        .description('Print the DESIGN.md content of an imported profile.')
        .action((id) => { void showCmd(id); });
    d.command('search <query...>')
        .description('Search imported profiles by id/title/archetype + DESIGN.md body. Ranked.')
        .option('--archetype <name>', 'Filter by archetype label')
        .option('--source <name>', 'Filter by source (awesome-design-md-core, design-md-extractor, etc.)')
        .option('--quality <letter>', 'Filter by quality score letter (A/B/C/D/F)')
        .option('--json', 'Emit JSON instead of human-readable.')
        .action((query, opts) => { void searchCmd(query, opts); });
    d.command('diff <a> <b>')
        .description('Token-level diff between two imported profiles (colors + typography + meta).')
        .option('--json', 'Emit JSON instead of human-readable.')
        .action((a, b, opts) => { void diffCmd(a, b, opts); });
    d.command('drift <profile> <url>')
        .description('Re-extract <url> and diff against the local <profile>. Verdict: in-sync / minor / notable / major drift.')
        .option('--json', 'Emit JSON instead of human-readable.')
        .action((profile, url, opts) => { void driftCmd(profile, url, opts); });
    d.command('extract <url>')
        .description('Extract a DESIGN.md from any public URL via the bundled extractor skill (provider auto-resolved).')
        .option('--out <dir>', 'Override output directory (default ~/.openlife/design-extract/<slug>/)')
        .option('--catalog', 'Also publish artifacts into design/profiles/<slug>/ for DesignMdRegistry')
        .option('--provider <id>', 'Force provider: claude-cli | openrouter (auto-resolved when omitted)')
        .option('--model <id>', 'Model id for openrouter (e.g. anthropic/claude-haiku-4-5)')
        .option('--compare <designPath>', 'Compare against an existing DESIGN.md and emit drift report')
        .option('--no-cache', 'Bypass the 24h cache and re-extract')
        .option('--no-content-gate', 'Skip the content-validation gate (bot/SPA detection)')
        .option('--timeout-ms <ms>', 'Total run cap (default 180000)', (v) => Number(v))
        .action((url, opts) => { void extractCmd(url, opts); });
}
