/**
 * US-19 — Engagement auto-status: planned → active.
 * Covers AC-19.1 → AC-19.4.
 */
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 = 'us19-redteam';
const PASS = 'us19-pass-strong';

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

async function createSimulation(token: string, engagementId: number, name = 'US-19 sim'): Promise<Simulation> {
  const r = await makeClient(token).post(`/engagements/${engagementId}/simulations`, { name });
  if (r.status !== 201) throw new Error(`create sim: ${r.status}`);
  return r.data as Simulation;
}

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

async function getEngagement(token: string, eid: number): Promise<{ status: string }> {
  const r = await makeClient(token).get(`/engagements/${eid}`);
  return r.data as { status: string };
}

test.describe('US-19 — engagement auto-status', () => {
  let redteamToken: string;

  test.beforeAll(async () => {
    await ensureUser(REDTEAM_USER, PASS, 'redteam');
    redteamToken = (await login(REDTEAM_USER, PASS)).token;
  });

  test.afterAll(async () => {
    try {
      const tok = await adminToken();
      await deleteUserByUsername(tok, REDTEAM_USER);
    } catch { /* noop */ }
  });

  test('AC-19.1 — engagement stays planned when sim is created (no auto-transition yet)', async () => {
    const eng = await createEngagement(redteamToken, {
      name: 'US-19 stay planned',
      start_date: '2026-01-01',
    });

    // Creating a simulation alone does NOT activate engagement
    const sim = await createSimulation(redteamToken, eng.id, 'AC-19.1 created');
    const engData = await getEngagement(redteamToken, eng.id);
    expect(engData.status).toBe('planned');

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

  test('AC-19.1 — engagement auto-activates when sim transitions to in_progress (via PATCH redteam field)', async () => {
    const eng = await createEngagement(redteamToken, {
      name: 'US-19 auto-activate',
      start_date: '2026-01-01',
    });
    expect(eng.status).toBe('planned');

    const sim = await createSimulation(redteamToken, eng.id, 'AC-19.1 trigger');
    // PATCH a redteam field → auto-transition sim to in_progress → engagement → active
    const r = await makeClient(redteamToken).patch(`/simulations/${sim.id}`, { name: 'trigger' });
    expect(r.status).toBe(200);
    expect(r.data.status).toBe('in_progress');

    const engData = await getEngagement(redteamToken, eng.id);
    expect(engData.status).toBe('active');

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

  test('AC-19.1 — engagement auto-activates when sim transitions via technique_ids', async () => {
    const eng = await createEngagement(redteamToken, {
      name: 'US-19 technique activate',
      start_date: '2026-01-01',
    });

    const sim = await createSimulation(redteamToken, eng.id, 'AC-19.1 technique');
    const r = await makeClient(redteamToken).patch(`/simulations/${sim.id}`, { technique_ids: ['T1059'] });
    expect(r.status).toBe(200);
    expect(r.data.status).toBe('in_progress');

    const engData = await getEngagement(redteamToken, eng.id);
    expect(engData.status).toBe('active');

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

  test('AC-19.1 — engagement auto-activates when sim transitions via tactic_ids', async () => {
    const eng = await createEngagement(redteamToken, {
      name: 'US-19 tactic activate',
      start_date: '2026-01-01',
    });

    const sim = await createSimulation(redteamToken, eng.id, 'AC-19.1 tactic');
    const r = await makeClient(redteamToken).patch(`/simulations/${sim.id}`, { tactic_ids: ['TA0007'] });
    expect(r.status).toBe(200);
    expect(r.data.status).toBe('in_progress');

    const engData = await getEngagement(redteamToken, eng.id);
    expect(engData.status).toBe('active');

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

  test('AC-19.2 — already active engagement stays active (no double-transition)', async () => {
    const eng = await createEngagement(redteamToken, {
      name: 'US-19 already active',
      start_date: '2026-01-01',
    });

    // First sim activates the engagement
    const sim1 = await createSimulation(redteamToken, eng.id, 'AC-19.2 first');
    await makeClient(redteamToken).patch(`/simulations/${sim1.id}`, { name: 'trigger 1' });
    const engAfterFirst = await getEngagement(redteamToken, eng.id);
    expect(engAfterFirst.status).toBe('active');

    // Second sim trigger — engagement stays active (not planned, not any other status)
    const sim2 = await createSimulation(redteamToken, eng.id, 'AC-19.2 second');
    await makeClient(redteamToken).patch(`/simulations/${sim2.id}`, { name: 'trigger 2' });
    const engAfterSecond = await getEngagement(redteamToken, eng.id);
    expect(engAfterSecond.status).toBe('active');

    await deleteSimulation(redteamToken, sim1.id);
    await deleteSimulation(redteamToken, sim2.id);
    await deleteEngagement(redteamToken, eng.id);
  });

  test('AC-19.3 — no backward auto transition: engagement status never goes back to planned', async () => {
    const eng = await createEngagement(redteamToken, {
      name: 'US-19 no backward',
      start_date: '2026-01-01',
    });

    const sim = await createSimulation(redteamToken, eng.id, 'AC-19.3 backward');
    await makeClient(redteamToken).patch(`/simulations/${sim.id}`, { name: 'trigger' });
    const engActive = await getEngagement(redteamToken, eng.id);
    expect(engActive.status).toBe('active');

    // Deleting the sim does not revert engagement to planned
    await deleteSimulation(redteamToken, sim.id);
    const engAfterDelete = await getEngagement(redteamToken, eng.id);
    expect(engAfterDelete.status).toBe('active');

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

  test('AC-19.4 — frontend invalidates engagement cache after simulation PATCH (badge updates without reload)', async ({
    page,
    context,
  }) => {
    const eng = await createEngagement(redteamToken, {
      name: 'US-19 frontend cache',
      start_date: '2026-01-01',
    });

    const sim = await createSimulation(redteamToken, eng.id, 'AC-19.4 cache');

    await seedTokenInStorage(context, redteamToken);
    // Navigate to engagement detail — engagement shows "planned"
    await page.goto(`/engagements/${eng.id}`);
    // Status badge should be planned initially
    const statusBadge = page.getByTestId('engagement-status-badge').first();
    if (await statusBadge.count() > 0) {
      await expect(statusBadge).toContainText(/planned/i);
    }

    // Now trigger in_progress via form
    await page.goto(`/engagements/${eng.id}/simulations/${sim.id}/edit`);
    const nameField = page.locator('#sim-name');
    await nameField.fill('trigger auto-active');
    await page.getByRole('button', { name: /save/i }).first().click();

    // Navigate back to engagement — status should now show active (cache invalidated)
    await page.goto(`/engagements/${eng.id}`);
    await page.waitForLoadState('networkidle');
    await expect(page.getByText(/active/i).first()).toBeVisible({ timeout: 5_000 });

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