import { describe, it, expect, vi } from 'vitest';
import express from 'express';
import cookieParser from 'cookie-parser';
import request from 'supertest';
import { requireOidcSession, requireTeamAccess } from './middleware';
import { createSessionToken } from './session';
import type { TeamDirectory } from './types';

const secret = new TextEncoder().encode('test-secret-at-least-32-bytes-long-ok');

function buildTestApp(teamDirectory: TeamDirectory) {
  const app = express();
  app.use(cookieParser());
  app.get(
    '/protected',
    requireOidcSession('session', secret, '/login'),
    requireTeamAccess(teamDirectory, ['progcom']),
    (req, res) => res.json({ username: req.eventerSession!.username, teams: req.eventerSession!.teams })
  );
  return app;
}

describe('requireOidcSession', () => {
  it('redirects to loginPath when there is no session cookie', async () => {
    const app = buildTestApp({ getTeamsForUser: vi.fn().mockResolvedValue(['progcom']) });
    const res = await request(app).get('/protected');
    expect(res.status).toBe(302);
    expect(res.headers.location).toBe('/login');
  });
});

describe('requireTeamAccess', () => {
  it('returns 403 when the user is on no candidate teams', async () => {
    const app = buildTestApp({ getTeamsForUser: vi.fn().mockResolvedValue([]) });
    const token = await createSessionToken({ username: 'j47ho' }, secret);
    const res = await request(app).get('/protected').set('Cookie', [`session=${token}`]);
    expect(res.status).toBe(403);
    expect(res.body.error).toBe('team_access_required');
  });

  it('passes through and attaches teams when the user is on a candidate team', async () => {
    const app = buildTestApp({ getTeamsForUser: vi.fn().mockResolvedValue(['progcom']) });
    const token = await createSessionToken({ username: 'j47ho' }, secret);
    const res = await request(app).get('/protected').set('Cookie', [`session=${token}`]);
    expect(res.status).toBe(200);
    expect(res.body).toEqual({ username: 'j47ho', teams: ['progcom'] });
  });

  it('returns 500 when the team directory throws', async () => {
    const app = buildTestApp({ getTeamsForUser: vi.fn().mockRejectedValue(new Error('LDAP down')) });
    const token = await createSessionToken({ username: 'j47ho' }, secret);
    const res = await request(app).get('/protected').set('Cookie', [`session=${token}`]);
    expect(res.status).toBe(500);
    expect(res.body.error).toBe('team_check_failed');
  });
});
