import { describe, expect, test, beforeEach, afterEach } from 'bun:test';
import { promises as fs } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { copyPublicAssets, PublicAssetCollisionError } from './copy-public-assets.js';
let tmp;
let projectRoot;
let outputDir;
beforeEach(async () => {
    tmp = await fs.mkdtemp(join(tmpdir(), 'public-assets-'));
    projectRoot = join(tmp, 'project');
    outputDir = projectRoot;
    await fs.mkdir(projectRoot, { recursive: true });
});
afterEach(async () => {
    await fs.rm(tmp, { recursive: true, force: true }).catch(() => { });
});
async function writePublic(rel, content) {
    const full = join(projectRoot, 'quickback', 'public', rel);
    await fs.mkdir(join(full, '..'), { recursive: true });
    await fs.writeFile(full, content);
}
async function readDest(rel) {
    return fs.readFile(join(outputDir, 'src', 'apps', rel));
}
async function pathExists(p) {
    try {
        await fs.access(p);
        return true;
    }
    catch {
        return false;
    }
}
describe('copyPublicAssets — quickback/public passthrough', () => {
    test('no-op when public folder is missing', async () => {
        const result = await copyPublicAssets({
            projectRoot,
            outputDir,
            manifestPaths: ['src/index.ts'],
        });
        expect(result.copied).toBe(0);
        expect(result.destPaths).toEqual([]);
        expect(await pathExists(join(outputDir, 'src', 'apps'))).toBe(false);
    });
    test('copies a single text file at the root of public/ to src/apps/', async () => {
        await writePublic('robots.txt', 'User-agent: *\nDisallow:\n');
        const result = await copyPublicAssets({
            projectRoot,
            outputDir,
            manifestPaths: ['src/index.ts'],
        });
        expect(result.copied).toBe(1);
        expect(result.destPaths).toContain(join('src', 'apps', 'robots.txt'));
        expect((await readDest('robots.txt')).toString('utf-8')).toBe('User-agent: *\nDisallow:\n');
    });
    test('preserves nested directory structure', async () => {
        await writePublic('.well-known/apple-app-site-association', '{}');
        await writePublic('og/og-image.png', Buffer.from([0x89, 0x50, 0x4e, 0x47]));
        const result = await copyPublicAssets({
            projectRoot,
            outputDir,
            manifestPaths: [],
        });
        // .well-known starts with a dot — it's filtered (hidden-entry rule).
        expect(result.copied).toBe(1);
        expect(result.destPaths).toContain(join('src', 'apps', 'og', 'og-image.png'));
        const png = await readDest('og/og-image.png');
        expect(png[0]).toBe(0x89);
        expect(png[3]).toBe(0x47);
    });
    test('preserves binary content byte-for-byte', async () => {
        // Random non-utf8 bytes — utf8 round-tripping would corrupt these.
        const bytes = Buffer.from([0xff, 0xfe, 0x00, 0x80, 0xc0, 0xff]);
        await writePublic('weird.bin', bytes);
        await copyPublicAssets({ projectRoot, outputDir, manifestPaths: [] });
        const out = await readDest('weird.bin');
        expect(Buffer.compare(out, bytes)).toBe(0);
    });
    test('skips hidden files and directories (.DS_Store, .git/, etc.)', async () => {
        await writePublic('.DS_Store', 'junk');
        await writePublic('.git/HEAD', 'ref: refs/heads/main');
        await writePublic('favicon.ico', 'icon-bytes');
        const result = await copyPublicAssets({
            projectRoot,
            outputDir,
            manifestPaths: [],
        });
        expect(result.copied).toBe(1);
        expect(result.destPaths).toContain(join('src', 'apps', 'favicon.ico'));
        expect(await pathExists(join(outputDir, 'src', 'apps', '.DS_Store'))).toBe(false);
        expect(await pathExists(join(outputDir, 'src', 'apps', '.git'))).toBe(false);
    });
    test('refuses to overwrite a compiler-emitted manifest path', async () => {
        await writePublic('cms/index.html', '<html>not the real shell</html>');
        await expect(copyPublicAssets({
            projectRoot,
            outputDir,
            manifestPaths: ['src/apps/cms/index.html', 'src/index.ts'],
        })).rejects.toBeInstanceOf(PublicAssetCollisionError);
        // Nothing should have been written when we threw.
        expect(await pathExists(join(outputDir, 'src', 'apps', 'cms'))).toBe(false);
    });
    test('reports every collision in one error, not just the first', async () => {
        await writePublic('cms/index.html', 'x');
        await writePublic('account/index.html', 'y');
        await writePublic('robots.txt', 'z');
        let err;
        try {
            await copyPublicAssets({
                projectRoot,
                outputDir,
                manifestPaths: ['src/apps/cms/index.html', 'src/apps/account/index.html'],
            });
        }
        catch (e) {
            err = e;
        }
        expect(err).toBeInstanceOf(PublicAssetCollisionError);
        expect(err.collisions).toHaveLength(2);
        const paths = err.collisions.map((c) => c.publicPath).sort();
        expect(paths).toEqual(['account/index.html', 'cms/index.html']);
    });
    test('empty public folder reports zero copied without erroring', async () => {
        await fs.mkdir(join(projectRoot, 'quickback', 'public'), { recursive: true });
        const result = await copyPublicAssets({
            projectRoot,
            outputDir,
            manifestPaths: ['src/index.ts'],
        });
        expect(result.copied).toBe(0);
        expect(result.sourceDir).toBeDefined();
    });
    test('outputDir distinct from projectRoot still resolves correctly', async () => {
        outputDir = join(tmp, 'dist');
        await fs.mkdir(outputDir, { recursive: true });
        await writePublic('logo.svg', '<svg/>');
        const result = await copyPublicAssets({
            projectRoot,
            outputDir,
            manifestPaths: [],
        });
        expect(result.copied).toBe(1);
        expect((await fs.readFile(join(outputDir, 'src', 'apps', 'logo.svg'))).toString())
            .toBe('<svg/>');
        // Source still in projectRoot, untouched.
        expect(await pathExists(join(projectRoot, 'quickback', 'public', 'logo.svg')))
            .toBe(true);
    });
});
//# sourceMappingURL=copy-public-assets.test.js.map