const express = require('express');
const fetch = require('node-fetch');

jest.mock('../database/mariadb', () => ({
  logToFile: jest.fn(),
}));

jest.mock('../database/sessionModel', () => ({
  validateSession: jest.fn(),
  deleteSession: jest.fn(),
}));

const { validateSession, deleteSession } = require('../database/sessionModel');
const sessionRoutes = require('../database/routes/sessionRoutes');

describe('session routes', () => {
  let server;
  let baseUrl;

  beforeEach((done) => {
    jest.clearAllMocks();

    const app = express();
    app.use(express.json());
    app.use('/api/sessions', sessionRoutes);

    server = app.listen(0, () => {
      baseUrl = `http://127.0.0.1:${server.address().port}`;
      done();
    });
  });

  afterEach((done) => {
    server.close(done);
  });

  test('validates sessions from stored session data instead of parsing token format', async () => {
    const sessionId = 'session_gm_1782220508444_yddd8d';
    validateSession.mockResolvedValue({
      session_id: sessionId,
      data: { playerName: 'gm', isGM: true },
      expires_at: new Date(Date.now() + 60_000),
    });

    const res = await fetch(`${baseUrl}/api/sessions/validate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ sessionId }),
    });

    expect(res.status).toBe(200);
    await expect(res.json()).resolves.toEqual({ valid: true, playerName: 'gm' });
    expect(validateSession).toHaveBeenCalledWith(sessionId);
  });

  test('accepts stored sessions even when token characters do not match legacy regex', async () => {
    const sessionId = 'session_player.name_1782220508444_ABC-123';
    validateSession.mockResolvedValue({
      session_id: sessionId,
      data: { playerName: 'player.name' },
      expires_at: new Date(Date.now() + 60_000),
    });

    const res = await fetch(`${baseUrl}/api/sessions/validate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ sessionId }),
    });

    expect(res.status).toBe(200);
    await expect(res.json()).resolves.toEqual({ valid: true, playerName: 'player.name' });
  });

  test('rejects missing or expired sessions', async () => {
    validateSession.mockResolvedValue(null);

    const res = await fetch(`${baseUrl}/api/sessions/validate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ sessionId: 'missing-session' }),
    });

    expect(res.status).toBe(401);
    await expect(res.json()).resolves.toEqual({ error: 'Invalid or expired session' });
  });

  test('deletes stored session on logout', async () => {
    deleteSession.mockResolvedValue(undefined);

    const res = await fetch(`${baseUrl}/api/sessions/logout`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ sessionId: 'session_gm_123' }),
    });

    expect(res.status).toBe(200);
    await expect(res.json()).resolves.toEqual({ success: true });
    expect(deleteSession).toHaveBeenCalledWith('session_gm_123');
  });
});
