import { describe, expect, test, beforeEach, afterEach } from 'bun:test';
import { promises as fs } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { prepareGeneratedDir } from './prepare-output.js';
let tmp;
beforeEach(async () => {
    tmp = await fs.mkdtemp(join(tmpdir(), 'prepare-gen-'));
});
afterEach(async () => {
    await fs.rm(tmp, { recursive: true, force: true }).catch(() => { });
});
async function writeFile(rel, content = 'x') {
    const full = join(tmp, ...rel.split('/'));
    await fs.mkdir(join(full, '..'), { recursive: true });
    await fs.writeFile(full, content);
}
async function fileExists(rel) {
    try {
        await fs.access(join(tmp, ...rel.split('/')));
        return true;
    }
    catch {
        return false;
    }
}
describe('prepareGeneratedDir — clean-slate compile output prep', () => {
    // User story: As a developer renaming a feature, I want the old feature
    // folder gone after compile — clean slate means no ghost dirs, no stale
    // .DS_Store files keeping deleted folders alive in the tree.
    test('wipes the existing target dir entirely (folders included)', async () => {
        await writeFile('src/features/old/schema.ts');
        await writeFile('src/features/old/.DS_Store');
        await writeFile('src/features/new/schema.ts');
        const result = await prepareGeneratedDir(tmp, 'src', ['src/features/new/schema.ts']);
        expect(result.wiped).toBe(true);
        expect(await fileExists('src')).toBe(false);
        expect(await fileExists('src/features/old/.DS_Store')).toBe(false);
    });
    // User story: As a developer running compile for the first time, I want
    // the helper to be a no-op — there's nothing to wipe yet.
    test('skips wipe when target dir does not exist', async () => {
        const result = await prepareGeneratedDir(tmp, 'src', ['src/index.ts']);
        expect(result.wiped).toBe(false);
        expect(result.skipped).toBe('no-existing-tree');
    });
    // User story: As a developer protected from compiler bugs, I want the
    // wipe to refuse to run when the compiler returned an empty manifest —
    // that's almost always a regression, and I'd rather keep my last
    // known-good output than lose it to a misfire.
    test('refuses to wipe when manifest has no files in the target dir', async () => {
        await writeFile('src/features/x/schema.ts');
        const result = await prepareGeneratedDir(tmp, 'src', ['package.json', 'wrangler.toml']);
        expect(result.wiped).toBe(false);
        expect(result.skipped).toBe('empty-manifest');
        expect(await fileExists('src/features/x/schema.ts')).toBe(true);
    });
    // User story: As a developer about to lose 60 generator-emitted files in
    // a wipe, I want a snapshot of src/ saved automatically so I can recover
    // if the compiler stopped emitting something I was depending on.
    test('archives the existing tree before wiping', async () => {
        await writeFile('src/features/old/schema.ts', 'PRE-WIPE CONTENT');
        await writeFile('src/lib/auth.ts');
        const archiveDir = join(tmp, 'quickback', '.archives');
        const result = await prepareGeneratedDir(tmp, 'src', ['src/lib/auth.ts'], { archiveDir });
        expect(result.wiped).toBe(true);
        expect(result.archivePath).toBeDefined();
        const archived = await fs.readdir(result.archivePath, { recursive: true });
        expect(archived).toContain(join('features', 'old', 'schema.ts'));
        expect(archived).toContain(join('lib', 'auth.ts'));
        const recovered = await fs.readFile(join(result.archivePath, 'features', 'old', 'schema.ts'), 'utf-8');
        expect(recovered).toBe('PRE-WIPE CONTENT');
    });
    // User story: As a developer who refactors aggressively, I want older
    // snapshots pruned automatically so .archives/ doesn't balloon — keeping
    // the most recent 3 is enough to walk back from a regret.
    test('prunes archives beyond archiveKeep, newest-first', async () => {
        const archiveDir = join(tmp, 'archives');
        await fs.mkdir(archiveDir, { recursive: true });
        for (const stamp of ['src-0001', 'src-0002', 'src-0003', 'src-0004']) {
            await fs.mkdir(join(archiveDir, stamp));
        }
        await writeFile('src/index.ts');
        await prepareGeneratedDir(tmp, 'src', ['src/index.ts'], {
            archiveDir,
            archiveKeep: 3,
        });
        const remaining = (await fs.readdir(archiveDir)).filter((d) => d.startsWith('src-'));
        expect(remaining.length).toBe(3);
        // Newest survives — pruning is alphabetical-descending.
        expect(remaining).toContain('src-0004');
        expect(remaining).not.toContain('src-0001');
    });
    // User story: As a developer running quickback compile back-to-back with
    // the archive turned on, I want to see consistent timestamps on the
    // archive directory so I can identify which snapshot came from which
    // compile if I need to recover.
    test('archive directory name includes a sortable ISO timestamp', async () => {
        await writeFile('src/index.ts');
        const archiveDir = join(tmp, 'archives');
        const result = await prepareGeneratedDir(tmp, 'src', ['src/index.ts'], { archiveDir });
        expect(result.archivePath).toMatch(/src-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}/);
    });
});
//# sourceMappingURL=prepare-output.test.js.map