import { test } from 'node:test';
import assert from 'node:assert/strict';

// Env vor dem Import setzen: supabase.js bricht ohne URL/Key ab, ADMIN_EMAILS
// und JWT_SECRET werden beim Modul-Load gelesen.
process.env.SUPABASE_URL ||= 'http://localhost';
process.env.SUPABASE_SERVICE_KEY ||= 'dummy';
process.env.JWT_SECRET = 'test-secret';
process.env.ADMIN_EMAILS = 'boss@x.ch';

const { roleOf, requireAuth } = await import('../src/auth.js');
const { sign } = await import('hono/jwt');

test('roleOf: Admin aus ADMIN_EMAILS', () => {
  assert.equal(roleOf({ email: 'boss@x.ch' }), 'admin');
  assert.equal(roleOf({ email: 'BOSS@X.CH' }), 'admin');
});

test('roleOf: Rolle aus app_metadata', () => {
  assert.equal(roleOf({ email: 'a@x.ch', app_metadata: { role: 'admin' } }), 'admin');
  assert.equal(roleOf({ email: 'a@x.ch', app_metadata: { role: 'editor' } }), 'editor');
  assert.equal(roleOf({ email: 'a@x.ch' }), 'user');
});

// Minimaler Hono-Kontext-Stub.
function fakeCtx(authHeader) {
  const store = {};
  return {
    req: { header: (h) => (h === 'Authorization' ? authHeader : undefined) },
    set: (k, v) => { store[k] = v; },
    get: (k) => store[k],
    json: (body, status = 200) => ({ __status: status, body }),
  };
}

test('requireAuth: gültiges Token wird lokal verifiziert', async () => {
  const token = await sign(
    { sub: 'u1', email: 'A@x.ch', app_metadata: { role: 'editor' }, exp: Math.floor(Date.now() / 1000) + 60 },
    'test-secret', 'HS256');
  let passed = false;
  const c = fakeCtx('Bearer ' + token);
  await requireAuth(c, async () => { passed = true; });
  assert.equal(passed, true);
  assert.equal(c.get('email'), 'a@x.ch');           // kleingeschrieben
  assert.equal(c.get('role'), 'editor');
  assert.equal(c.get('canModerate'), true);
  assert.equal(c.get('isAdmin'), false);
});

test('requireAuth: fehlendes Token → 401', async () => {
  const c = fakeCtx('');
  const r = await requireAuth(c, async () => { throw new Error('darf nicht laufen'); });
  assert.equal(r.__status, 401);
});

test('requireAuth: kaputtes/falsch signiertes Token → 401', async () => {
  const bad = await sign({ sub: 'u1', exp: Math.floor(Date.now() / 1000) + 60 }, 'falsches-secret', 'HS256');
  for (const t of ['Bearer garbage', 'Bearer ' + bad]) {
    const r = await requireAuth(fakeCtx(t), async () => { throw new Error('darf nicht laufen'); });
    assert.equal(r.__status, 401);
  }
});

test('requireAuth: abgelaufenes Token → 401', async () => {
  const expired = await sign({ sub: 'u1', exp: Math.floor(Date.now() / 1000) - 10 }, 'test-secret', 'HS256');
  const r = await requireAuth(fakeCtx('Bearer ' + expired), async () => { throw new Error('darf nicht laufen'); });
  assert.equal(r.__status, 401);
});
