/**
 * US-22 — Refonte input MITRE dans le form.
 * Covers AC-22.1 → AC-22.5.
 * Key change: no "Add technique" / "Quick search" text buttons.
 * Instead: inline autocomplete input + grid icon for matrix.
 * Chips show T-id only (name in title=).
 */
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 = 'us22-redteam';
const SOC_USER = 'us22-soc';
const PASS = 'us22-pass-strong';

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

async function createSimulation(token: string, engagementId: number, name = 'US-22 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}`);
}

test.describe('US-22 — MITRE input redesign', () => {
  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-22 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-22.1 — layout: inline autocomplete input + matrix icon present, NO text buttons', async ({
    page,
    context,
  }) => {
    const sim = await createSimulation(redteamToken, engagementId, 'AC-22.1 layout');

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

    // Matrix icon button present
    await expect(page.getByLabel(/open mitre matrix/i)).toBeVisible();

    // Search input placeholder visible (inline autocomplete)
    await expect(page.getByText(/search technique/i)).toBeVisible();

    // No old-style text buttons
    await expect(page.getByRole('button', { name: /add technique/i })).not.toBeVisible();
    await expect(page.getByRole('button', { name: /quick search/i })).not.toBeVisible();

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

  test('AC-22.1 — inline autocomplete: click input shows combobox, type shows dropdown', async ({
    page,
    context,
  }) => {
    const sim = await createSimulation(redteamToken, engagementId, 'AC-22.1 autocomplete');

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

    // Click the fake-input placeholder to reveal the combobox
    await page.getByText(/search technique/i).click();
    const picker = page.getByRole('combobox', { name: /mitre technique/i });
    await expect(picker).toBeVisible();

    // Type to get results
    await picker.fill('T1059');
    const listbox = page.getByRole('listbox', { name: /mitre techniques/i });
    await expect(listbox).toBeVisible({ timeout: 5_000 });

    // Select via keyboard
    await picker.press('ArrowDown');
    await picker.press('Enter');

    // Tag appears
    await expect(page.getByTestId('techniques-tag-list')).toContainText('T1059', { timeout: 5_000 });
    // Auto-save toast
    await expect(page.getByText(/techniques updated/i)).toBeVisible({ timeout: 5_000 });

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

  test('AC-22.1 — matrix icon opens MitreMatrixModal', async ({
    page,
    context,
  }) => {
    const sim = await createSimulation(redteamToken, engagementId, 'AC-22.1 matrix icon');

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

    await page.getByLabel(/open mitre matrix/i).click();
    await expect(page.getByRole('dialog')).toBeVisible({ timeout: 10_000 });
    await expect(page.getByRole('dialog')).toContainText(/mitre att&?ck matrix/i);

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

  // AC-22.2 — chips show T-id only, name in title
  test('AC-22.2 — technique chips display T-id only, name in title= attribute', async ({
    page,
    context,
  }) => {
    const sim = await createSimulation(redteamToken, engagementId, 'AC-22.2 chip format');
    await makeClient(redteamToken).patch(`/simulations/${sim.id}`, { technique_ids: ['T1059'] });

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

    const chip = page.getByTestId('mitre-technique-tag').first();
    await expect(chip).toBeVisible();

    // Text content is T-id only
    const text = await chip.textContent();
    expect(text?.trim()).toMatch(/^T1059/);
    // Must NOT contain the full name inline
    expect(text).not.toMatch(/Command and Scripting Interpreter/);

    // Name appears in title attribute
    const title = await chip.getAttribute('title');
    expect(title).toMatch(/T1059/);
    expect(title).toMatch(/Command and Scripting Interpreter/);

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

  test('AC-22.2 — tactic chips display TA-id only, name in title= attribute', async ({
    page,
    context,
  }) => {
    const sim = await createSimulation(redteamToken, engagementId, 'AC-22.2 tactic chip format');
    await makeClient(redteamToken).patch(`/simulations/${sim.id}`, { tactic_ids: ['TA0007'] });

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

    const chip = page.getByTestId('mitre-tactic-tag').first();
    await expect(chip).toBeVisible();

    const text = await chip.textContent();
    expect(text?.trim()).toMatch(/^TA0007/);
    expect(text).not.toMatch(/Discovery/);

    const title = await chip.getAttribute('title');
    expect(title).toMatch(/TA0007/);
    expect(title).toMatch(/Discovery/);

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

  // AC-22.4 — empty state
  test('AC-22.4 — empty state: "No techniques selected" visible, input and matrix icon still shown', async ({
    page,
    context,
  }) => {
    const sim = await createSimulation(redteamToken, engagementId, 'AC-22.4 empty');

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

    // Empty state message
    await expect(page.getByText(/no techniques selected/i)).toBeVisible();

    // Input and matrix icon still present in non-disabled mode
    await expect(page.getByLabel(/open mitre matrix/i)).toBeVisible();
    await expect(page.getByText(/search technique/i)).toBeVisible();

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

  // AC-22.5 — read-only mode
  test('AC-22.5 — SOC on in_progress sim: chips visible (no ×), input + matrix icon hidden', async ({
    page,
    context,
  }) => {
    const sim = await createSimulation(redteamToken, engagementId, 'AC-22.5 soc readonly');
    // Add a technique and advance to review_required for SOC access
    await makeClient(redteamToken).patch(`/simulations/${sim.id}`, { technique_ids: ['T1059'] });
    await makeClient(redteamToken).post(`/simulations/${sim.id}/transition`, { to: 'review_required' });

    await seedTokenInStorage(context, socToken);
    await page.goto(`/engagements/${engagementId}/simulations/${sim.id}/edit`);

    // Chip is visible
    await expect(page.getByTestId('mitre-technique-tag')).toBeVisible();

    // No × remove button (read-only for SOC on technique chips)
    await expect(page.getByRole('button', { name: /remove T1059/i })).not.toBeVisible();

    // Matrix icon and input hidden in disabled mode
    await expect(page.getByLabel(/open mitre matrix/i)).not.toBeVisible();
    await expect(page.getByText(/search technique/i)).not.toBeVisible();

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

  test('AC-22.5 — done sim: all chips read-only, no input', async ({
    page,
    context,
  }) => {
    const sim = await createSimulation(redteamToken, engagementId, 'AC-22.5 done readonly');
    await makeClient(redteamToken).patch(`/simulations/${sim.id}`, { technique_ids: ['T1059'] });
    // Drive to done
    await makeClient(redteamToken).post(`/simulations/${sim.id}/transition`, { to: 'review_required' });
    await makeClient(redteamToken).post(`/simulations/${sim.id}/transition`, { to: 'done' });

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

    // Chip visible
    await expect(page.getByTestId('mitre-technique-tag')).toBeVisible();
    // No × remove
    await expect(page.getByRole('button', { name: /remove T1059/i })).not.toBeVisible();
    // No matrix icon
    await expect(page.getByLabel(/open mitre matrix/i)).not.toBeVisible();

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