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

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

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

const { playerHelpers } = require('../database/mariadb');
const { createSession } = require('../database/sessionModel');
const playerRoutes = require('../database/routes/playerRoutes');

describe('player login route', () => {
  let server;
  let baseUrl;
  const originalPlayerPassword = process.env.PLAYER_PASSWORD;

  beforeEach((done) => {
    jest.clearAllMocks();
    delete process.env.PLAYER_PASSWORD;
    createSession.mockResolvedValue(undefined);

    const app = express();
    app.use(express.json());
    app.use('/api/players', playerRoutes);

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

  afterEach((done) => {
    if (originalPlayerPassword === undefined) {
      delete process.env.PLAYER_PASSWORD;
    } else {
      process.env.PLAYER_PASSWORD = originalPlayerPassword;
    }
    server.close(done);
  });

  test('logs in a regular player with their stored plain password', async () => {
    playerHelpers.getByName.mockResolvedValue({
      name: 'anders',
      pw: 'stored-player-password',
      pwHash: '',
    });

    const res = await fetch(`${baseUrl}/api/players/login`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: 'anders', password: 'stored-player-password' }),
    });
    const body = await res.json();

    expect(res.status).toBe(200);
    expect(body.success).toBe(true);
    expect(body.player).toEqual({ name: 'anders' });
    expect(body.sessionId).toMatch(/^session_anders_/);
  });

  test('logs in a regular player with their stored hashed password', async () => {
    const hash = await bcrypt.hash('hashed-player-password', 4);
    playerHelpers.getByName.mockResolvedValue({
      name: 'claes',
      pw: '',
      pwHash: hash,
    });

    const res = await fetch(`${baseUrl}/api/players/login`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: 'claes', password: 'hashed-player-password' }),
    });

    expect(res.status).toBe(200);
    await expect(res.json()).resolves.toMatchObject({
      success: true,
      player: { name: 'claes' },
    });
  });

  test('uses the player UI default when no stored or environment password exists', async () => {
    playerHelpers.getByName.mockResolvedValue({
      name: 'phillip',
      pw: '',
      pwHash: '',
    });

    const res = await fetch(`${baseUrl}/api/players/login`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: 'phillip', password: '1234' }),
    });

    expect(res.status).toBe(200);
  });

  test('rejects an incorrect regular player password', async () => {
    playerHelpers.getByName.mockResolvedValue({
      name: 'christoffer',
      pw: 'stored-player-password',
      pwHash: '',
    });

    const res = await fetch(`${baseUrl}/api/players/login`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: 'christoffer', password: 'wrong-password' }),
    });

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