import { describe, it, expect } from 'vitest';
import { onRequest } from '../src/middleware';
import { createSession, ADMIN_COOKIE } from '../src/lib/auth';

const NEXT_SENTINEL = new Response('next-ok', { status: 200 });
const next = async () => NEXT_SENTINEL;

function makeContext(url: string, cookieValue?: string) {
  return {
    url: new URL(url),
    cookies: {
      get: (name: string) =>
        name === ADMIN_COOKIE && cookieValue !== undefined ? { value: cookieValue } : undefined,
    },
    redirect: (path: string) =>
      new Response(null, { status: 302, headers: { Location: path } }),
  } as Parameters<typeof onRequest>[0];
}

async function run(url: string, cookieValue?: string) {
  return (await onRequest(makeContext(url, cookieValue), next as Parameters<typeof onRequest>[1])) as Response;
}

describe('middleware — routes publiques', () => {
  it('/ sans cookie → next', async () => {
    const res = await run('http://localhost/');
    expect(res).toBe(NEXT_SENTINEL);
  });

  it('/admin/login sans cookie → next (page de login publique)', async () => {
    const res = await run('http://localhost/admin/login');
    expect(res).toBe(NEXT_SENTINEL);
  });

  it('/api/auth/login sans cookie → next (route publique)', async () => {
    const res = await run('http://localhost/api/auth/login');
    expect(res).toBe(NEXT_SENTINEL);
  });
});

describe('middleware — pages admin', () => {
  it('/admin sans cookie → redirect /admin/login', async () => {
    const res = await run('http://localhost/admin');
    expect(res.status).toBe(302);
    expect(res.headers.get('Location')).toBe('/admin/login');
  });

  it('/admin/projets sans cookie → redirect /admin/login', async () => {
    const res = await run('http://localhost/admin/projets');
    expect(res.status).toBe(302);
    expect(res.headers.get('Location')).toBe('/admin/login');
  });

  it('/admin/projets avec token valide → next', async () => {
    const token = await createSession();
    const res = await run('http://localhost/admin/projets', token);
    expect(res).toBe(NEXT_SENTINEL);
  });

  it('/admin/projets avec token invalide → redirect /admin/login', async () => {
    const res = await run('http://localhost/admin/projets', 'not.a.real.jwt');
    expect(res.status).toBe(302);
    expect(res.headers.get('Location')).toBe('/admin/login');
  });
});

describe('middleware — APIs admin', () => {
  it('/api/content/profile sans cookie → 401 JSON', async () => {
    const res = await run('http://localhost/api/content/profile');
    expect(res.status).toBe(401);
    expect(await res.json()).toEqual({ error: 'unauthorized' });
  });

  it('/api/upload sans cookie → 401 JSON', async () => {
    const res = await run('http://localhost/api/upload');
    expect(res.status).toBe(401);
  });

  it('/api/auth/logout sans cookie → 401 JSON', async () => {
    const res = await run('http://localhost/api/auth/logout');
    expect(res.status).toBe(401);
  });

  it('/api/content/profile avec token invalide → 401 JSON', async () => {
    const res = await run('http://localhost/api/content/profile', 'garbage');
    expect(res.status).toBe(401);
  });

  it('/api/content/profile avec token valide → next', async () => {
    const token = await createSession();
    const res = await run('http://localhost/api/content/profile', token);
    expect(res).toBe(NEXT_SENTINEL);
  });
});
