/**
 * US-7 — redteam creates a simulation inside an engagement.
 * Covers AC-7.1 → AC-7.6.
 */
import { test, expect } from '@playwright/test';
import {
  adminToken,
  createEngagement,
  deleteEngagement,
  deleteUserByUsername,
  ensureUser,
  login,
  makeClient,
} from '../fixtures/api';
import { seedTokenInStorage } from '../fixtures/auth';

const REDTEAM_USER = 'us7-redteam';
const SOC_USER = 'us7-soc';
const PASS = 'us7-pass-strong';

interface Simulation {
  id: number;
  engagement_id: number;
  name: string;
  status: string;
  created_at: string;
  [key: string]: unknown;
}

async function createSimulation(
  token: string,
  engagementId: number,
  payload: { name: string },
): Promise<Simulation> {
  const client = makeClient(token);
  const r = await client.post(`/engagements/${engagementId}/simulations`, payload);
  if (r.status !== 201) {
    throw new Error(`create simulation failed: ${r.status} ${JSON.stringify(r.data)}`);
  }
  return r.data as Simulation;
}

async function deleteSimulation(token: string, simId: number): Promise<void> {
  const client = makeClient(token);
  await client.delete(`/simulations/${simId}`);
}

test.describe('US-7 — simulation create', () => {
  let redteamToken: string;
  let socToken: string;
  let engagementId: number;

  test.beforeAll(async () => {
    await ensureUser(REDTEAM_USER, PASS, 'redteam');
    await ensureUser(SOC_USER, PASS, 'soc');
    redteamToken = (await login(REDTEAM_USER, PASS)).token;
    socToken = (await login(SOC_USER, PASS)).token;
    const eng = await createEngagement(redteamToken, {
      name: 'US-7 Test Engagement',
      start_date: '2026-01-01',
    });
    engagementId = eng.id;
  });

  test.afterAll(async () => {
    try {
      const tok = await adminToken();
      await deleteEngagement(tok, engagementId);
      for (const u of [REDTEAM_USER, SOC_USER]) {
        await deleteUserByUsername(tok, u);
      }
    } catch {
      /* noop */
    }
  });

  test('AC-7.1 — POST creates simulation with status pending, name required', async () => {
    const sim = await createSimulation(redteamToken, engagementId, { name: 'Test sim 7.1' });
    expect(sim.id).toBeTruthy();
    expect(sim.engagement_id).toBe(engagementId);
    expect(sim.name).toBe('Test sim 7.1');
    expect(sim.status).toBe('pending');
    expect(sim.created_at).toBeTruthy();

    // name required: blank name → 400
    const client = makeClient(redteamToken);
    const r = await client.post(`/engagements/${engagementId}/simulations`, { name: '' });
    expect(r.status).toBe(400);

    await deleteSimulation(redteamToken, sim.id);
  });

  test('AC-7.2 — soc role → 403 on POST', async () => {
    const client = makeClient(socToken);
    const r = await client.post(`/engagements/${engagementId}/simulations`, {
      name: 'soc-blocked',
    });
    expect(r.status).toBe(403);
  });

  test('AC-7.3 — unknown engagement → 404; existing engagement with no sims → empty list', async () => {
    const client = makeClient(redteamToken);

    const r404 = await client.post('/engagements/999999/simulations', { name: 'ghost' });
    expect(r404.status).toBe(404);

    // Create a fresh engagement with no sims and verify list is empty
    const freshEng = await createEngagement(redteamToken, {
      name: 'US-7 empty engagement',
      start_date: '2026-01-01',
    });
    const listR = await client.get(`/engagements/${freshEng.id}/simulations`);
    expect(listR.status).toBe(200);
    expect(listR.data).toEqual([]);

    await deleteEngagement(redteamToken, freshEng.id);
  });

  test('AC-7.4 — GET list returns sims ordered by created_at desc', async () => {
    const client = makeClient(redteamToken);

    const s1 = await createSimulation(redteamToken, engagementId, { name: 'First sim' });
    // Small delay so created_at timestamps differ
    await new Promise((r) => setTimeout(r, 50));
    const s2 = await createSimulation(redteamToken, engagementId, { name: 'Second sim' });

    const listR = await client.get(`/engagements/${engagementId}/simulations`);
    expect(listR.status).toBe(200);
    const list: Simulation[] = listR.data;
    expect(list.length).toBeGreaterThanOrEqual(2);
    // Most recent first
    const ids = list.map((s) => s.id);
    expect(ids.indexOf(s2.id)).toBeLessThan(ids.indexOf(s1.id));

    await deleteSimulation(redteamToken, s1.id);
    await deleteSimulation(redteamToken, s2.id);
  });

  test('AC-7.5 — /engagements/:eid shows Simulations section with list + "Nouvelle simulation" button for redteam', async ({
    page,
    context,
  }) => {
    const sim = await createSimulation(redteamToken, engagementId, { name: 'Visible sim' });

    await seedTokenInStorage(context, redteamToken);
    await page.goto(`/engagements/${engagementId}`);

    // Simulations section visible
    await expect(page.getByRole('heading', { name: /simulations/i })).toBeVisible();

    // Required columns
    for (const col of ['Name', 'MITRE', 'Status', 'Executed at']) {
      await expect(page.getByRole('columnheader', { name: new RegExp(col, 'i') })).toBeVisible();
    }

    // The created simulation row is visible
    await expect(page.getByRole('row', { name: /Visible sim/i })).toBeVisible();

    // "Nouvelle simulation" button visible for redteam
    await expect(
      page.getByRole('link', { name: /nouvelle simulation/i }),
    ).toBeVisible();

    // SOC should NOT see "Nouvelle simulation" button
    await seedTokenInStorage(context, socToken);
    await page.goto(`/engagements/${engagementId}`);
    await expect(page.getByRole('link', { name: /nouvelle simulation/i })).toHaveCount(0);

    await deleteSimulation(redteamToken, sim.id);
  });

  test('AC-7.6 — clicking a simulation row navigates to /engagements/:eid/simulations/:sid/edit', async ({
    page,
    context,
  }) => {
    const sim = await createSimulation(redteamToken, engagementId, { name: 'Click me sim' });

    await seedTokenInStorage(context, redteamToken);
    await page.goto(`/engagements/${engagementId}`);

    // Click the sim name link
    await page.getByRole('link', { name: 'Click me sim' }).click();
    await page.waitForURL(
      new RegExp(`/engagements/${engagementId}/simulations/${sim.id}/edit`),
    );
    await expect(page.url()).toContain(
      `/engagements/${engagementId}/simulations/${sim.id}/edit`,
    );

    await deleteSimulation(redteamToken, sim.id);
  });
});
