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

jest.mock('../database/mariadb', () => ({
  missionHelpers: {
    getAll: jest.fn(),
    getById: jest.fn(),
    getActive: jest.fn(),
    create: jest.fn(),
    update: jest.fn(),
    setActive: jest.fn(),
    updateProgress: jest.fn(),
    delete: jest.fn(),
  },
  missionRollHelpers: {
    getActive: jest.fn(),
    create: jest.fn(),
    delete: jest.fn(),
  },
  logToFile: jest.fn(),
}));

const { missionHelpers, missionRollHelpers } = require('../database/mariadb');
const missionRoutes = require('../database/routes/missionRoutes');

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

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

    const app = express();
    app.use(express.json());
    app.use('/api/missions', missionRoutes);

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

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

  test('returns the active mission', async () => {
    missionHelpers.getActive.mockResolvedValue({
      id: 9,
      name: 'The Hunt',
      current_scene: 1,
      scenes: [{ title: 'Briefing' }, { title: 'Contact' }],
    });

    const res = await fetch(`${baseUrl}/api/missions/active/current`);

    expect(res.status).toBe(200);
    await expect(res.json()).resolves.toMatchObject({
      id: 9,
      name: 'The Hunt',
      current_scene: 1,
    });
  });

  test('returns only the current scene for player active mission', async () => {
    missionHelpers.getActive.mockResolvedValue({
      id: 9,
      name: 'The Hunt',
      current_scene: 1,
      scenes: [
        { title: 'Briefing', description: 'Old scene' },
        { title: 'Contact', description: 'Current player scene', gmNotes: 'secret plan', objectives: ['Advance'] },
        { title: 'Hidden Future', description: 'Not for players yet' },
      ],
      enemy_count: 59,
      gm_player: 'gm',
    });

    const res = await fetch(`${baseUrl}/api/missions/active/player`);

    expect(res.status).toBe(200);
    await expect(res.json()).resolves.toEqual({
      id: 9,
      name: 'The Hunt',
      current_scene: 0,
      active_scene_index: 1,
      scenes: [{ title: 'Contact', description: 'Current player scene', objectives: ['Advance'] }],
    });
  });

  test('sets the active mission', async () => {
    missionHelpers.setActive.mockResolvedValue(true);
    missionHelpers.getById.mockResolvedValue({ id: 9, name: 'The Hunt', is_active: true, scenes: [] });

    const res = await fetch(`${baseUrl}/api/missions/9/active`, { method: 'POST' });

    expect(res.status).toBe(200);
    await expect(res.json()).resolves.toMatchObject({
      success: true,
      mission: { id: 9, is_active: true },
    });
    expect(missionHelpers.setActive).toHaveBeenCalledWith('9');
  });

  test('returns active mission roll feed', async () => {
    missionRollHelpers.getActive.mockResolvedValue([
      { id: 1, player_name: 'anders', roll_type: 'check', label: 'Awareness', payload: { roll: 22, target: 45, success: true } },
    ]);

    const res = await fetch(`${baseUrl}/api/missions/active/rolls/feed`);

    expect(res.status).toBe(200);
    await expect(res.json()).resolves.toMatchObject([
      { id: 1, player_name: 'anders', label: 'Awareness' },
    ]);
    expect(missionRollHelpers.getActive).toHaveBeenCalledWith(50);
  });

  test('records a mission roll', async () => {
    missionRollHelpers.create.mockResolvedValue(12);

    const body = { playerName: 'anders', rollType: 'check', label: 'Awareness', payload: { roll: 22 } };
    const res = await fetch(`${baseUrl}/api/missions/rolls`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });

    expect(res.status).toBe(200);
    await expect(res.json()).resolves.toEqual({ success: true, id: 12 });
    expect(missionRollHelpers.create).toHaveBeenCalledWith(body);
  });

  test('deletes a mission roll', async () => {
    missionRollHelpers.delete.mockResolvedValue(true);

    const res = await fetch(`${baseUrl}/api/missions/rolls/12`, { method: 'DELETE' });

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

  test('updates mission progress', async () => {
    const scenes = [{ title: 'Briefing', completed: true }, { title: 'Contact' }];
    missionHelpers.updateProgress.mockResolvedValue(true);
    missionHelpers.getById.mockResolvedValue({ id: 9, current_scene: 1, scenes });

    const res = await fetch(`${baseUrl}/api/missions/9/progress`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ currentScene: 1, scenes }),
    });

    expect(res.status).toBe(200);
    await expect(res.json()).resolves.toMatchObject({
      success: true,
      mission: { id: 9, current_scene: 1 },
    });
    expect(missionHelpers.updateProgress).toHaveBeenCalledWith('9', { currentScene: 1, scenes });
  });
});
