/**
 * studiograph admin migrate-asset-owners — one-time owner rewrite for the
 * assets-referenced-not-owned model (P1).
 *
 * Rewrites every `assets.db` row whose owner is an ENTITY (owner_type outside
 * {folder, workspace}) to a folder asset of its current repo:
 * owner_type='folder', owner_id=<repo>. After this, assets are uniformly
 * library citizens — entries only ever REFERENCE them (via the immutable
 * /api/assets/{assetId}/{filename} URL), never own them.
 *
 * Safety:
 *   - `--dry-run`: reports the per-repo breakdown + counts, writes nothing.
 *   - Idempotent: the rewrite matches only entity-owned rows, so a second run
 *     is a no-op (0 rows).
 *   - Blobs untouched: immutable keys are repo-independent; this is an
 *     index-row-only UPDATE. Fully reversible, no blob moves.
 *   - Orphan-owner rows (owner entity already deleted) home to the repo like
 *     any other row — they surface as library assets, never deleted.
 *   - Verification: COUNT(*) of remaining entity-owned rows must be 0 after a
 *     real run; a non-zero count exits 1. (This query originally gated the
 *     P1.5 dead-code delete, which has landed — uploads now structurally
 *     refuse entity owners, so this command is the one-time repair for rows
 *     that predate P1.)
 *
 * Per-workspace: run on each serving instance (assets.db is volume-local),
 * like `admin migrate-assets`.
 */
import { Command } from 'commander';
import { intro, outro, log } from '@clack/prompts';
import { Workspace } from '../../../core/workspace.js';
import { WorkspaceManager } from '../../../core/workspace-manager.js';
/**
 * Core migration — decoupled from clack/Workspace so it's unit-testable with
 * a real AssetIndexService over a temp workspace. Index-only; never touches
 * blobs or markdown.
 */
export function runAssetOwnerMigration(assetIndex, dryRun, knownRepos) {
    const breakdown = assetIndex.summarizeEntityOwned();
    const entityOwned = breakdown.reduce((n, b) => n + b.count, 0);
    const unknownRepos = knownRepos
        ? [...new Set(breakdown.map(b => b.repo).filter(r => !knownRepos.has(r)))]
        : [];
    const rewritten = dryRun ? 0 : assetIndex.rehomeEntityOwnedToFolder();
    // The verification re-count must be a FRESH query after a real run; in
    // dry-run nothing was written, so it equals the pre-count by construction.
    const remaining = dryRun ? entityOwned : assetIndex.countEntityOwned();
    return { entityOwned, rewritten, remaining, breakdown, unknownRepos };
}
export const adminMigrateAssetOwnersCommand = new Command('migrate-asset-owners')
    .description("Rewrite entity-owned assets.db rows to folder ownership (assets are referenced, never owned)")
    .option('--dry-run', 'Report what would change (per-repo breakdown + counts); write nothing')
    .action(async (opts) => {
    intro(opts.dryRun ? 'Asset owner migration (DRY RUN)' : 'Asset owner migration');
    const workspace = new Workspace();
    if (!workspace.isWorkspace()) {
        outro('Not a Studiograph workspace. Run from your workspace root.');
        process.exit(1);
        return;
    }
    const config = await workspace.loadConfig();
    const gitUser = { id: 'migration', name: 'Asset Migration', email: 'migration@studiograph.local' };
    const wm = new WorkspaceManager(process.cwd(), config, gitUser);
    const assetIndex = wm.getAssetIndex();
    const report = runAssetOwnerMigration(assetIndex, !!opts.dryRun, new Set(config.repos.map(r => r.name)));
    assetIndex.close();
    if (report.breakdown.length > 0) {
        log.info('Entity-owned rows by (repo, owner_type):\n' +
            report.breakdown.map(b => `  ${b.repo} ${b.ownerType}: ${b.count}`).join('\n'));
    }
    if (report.unknownRepos.length > 0) {
        log.warn(`Rows reference repos not in workspace config (already unreachable; ` +
            `rewritten but never listed): ${report.unknownRepos.join(', ')}`);
    }
    log.info(`Entity-owned rows found: ${report.entityOwned}\n` +
        `${opts.dryRun ? 'Would rewrite' : 'Rewritten'} to folder ownership: ${opts.dryRun ? report.entityOwned : report.rewritten}\n` +
        `Remaining entity-owned (verification, must be 0 post-run): ${report.remaining}`);
    if (!opts.dryRun && report.remaining !== 0) {
        outro(`VERIFICATION FAILED: ${report.remaining} entity-owned row(s) remain. Investigate before the P1.5 cleanup.`);
        process.exit(1);
        return;
    }
    outro(opts.dryRun
        ? 'Dry run complete — no changes written.'
        : `Migration complete — ${report.rewritten} row(s) re-homed to their folder; blobs untouched.`);
});
//# sourceMappingURL=migrate-asset-owners.js.map