import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { mkdtemp, mkdir, writeFile, rm } from 'node:fs/promises';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import type { APIRoute } from 'astro';
let workDir: string;
let GET: APIRoute;

// PNG 1x1 transparent minimal
const PNG_1X1 = Buffer.from(
  '89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c4890000000a49444154789c63000100000005000100' +
    '0d0a2db40000000049454e44ae426082',
  'hex',
);

async function setupTmpRoot() {
  workDir = await mkdtemp(join(tmpdir(), 'portfolio-files-'));
  await mkdir(join(workDir, 'data', 'uploads', 'img'), { recursive: true });
  await writeFile(join(workDir, 'data', 'uploads', 'img', 'test.png'), PNG_1X1);
  vi.spyOn(process, 'cwd').mockReturnValue(workDir);
  vi.resetModules();
  const mod = await import('../../src/pages/api/files/[...path]');
  GET = mod.GET as APIRoute;
}

async function cleanup() {
  vi.restoreAllMocks();
  if (workDir) await rm(workDir, { recursive: true, force: true });
}

beforeEach(setupTmpRoot);
afterEach(cleanup);

function call(pathParam: string) {
  return GET({ params: { path: pathParam } } as unknown as Parameters<APIRoute>[0]) as Promise<Response>;
}

describe('GET /api/files/[...path]', () => {
  it('retourne 404 si path vide', async () => {
    const res = await call('');
    expect(res.status).toBe(404);
  });

  it('bloque le path traversal classique (../../etc/passwd)', async () => {
    const res = await call('../../etc/passwd');
    expect(res.status).toBe(403);
  });

  it('bloque le path traversal imbriqué (img/../../../etc/passwd)', async () => {
    const res = await call('img/../../../etc/passwd');
    expect(res.status).toBe(403);
  });

  it('chemin absolu (/etc/passwd) est aplati dans UPLOADS_ROOT → 404 sans accès au vrai /etc/passwd', async () => {
    const res = await call('/etc/passwd');
    expect(res.status).toBe(404);
  });

  it('retourne 404 sur un fichier inexistant dans uploads', async () => {
    const res = await call('img/missing.png');
    expect(res.status).toBe(404);
  });

  it('sert un fichier valide avec le bon Content-Type', async () => {
    const res = await call('img/test.png');
    expect(res.status).toBe(200);
    expect(res.headers.get('Content-Type')).toBe('image/png');
    const body = Buffer.from(await res.arrayBuffer());
    expect(body.equals(PNG_1X1)).toBe(true);
  });
});
