import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { screen, waitFor } from '@testing-library/react';
import { Route, Routes } from 'react-router-dom';
import MockAdapter from 'axios-mock-adapter';
import { apiClient } from '@/api/client';
import { SimulationFormPage } from '@/pages/SimulationFormPage';
import { renderWithProviders } from './utils';
import type { Simulation } from '@/api/types';

const BASE_SIM: Simulation = {
  id: 7,
  engagement_id: 42,
  name: 'Recon test',
  techniques: [],
  tactics: [],
  description: 'Some description',
  commands: 'whoami\nipconfig',
  prerequisites: null,
  executed_at: null,
  execution_result: null,
  log_source: null,
  logs: null,
  soc_comment: null,
  incident_number: null,
  status: 'pending',
  created_at: '2026-05-26T08:00:00',
  updated_at: null,
  created_by: { id: 1, username: 'alice' },
};

let mockRole: 'admin' | 'redteam' | 'soc' = 'redteam';

vi.mock('@/hooks/useAuth', () => ({
  useAuth: () => ({
    user: { id: 1, username: 'alice', role: mockRole, created_at: '2026-01-01' },
    status: 'authenticated',
    login: vi.fn(),
    logout: vi.fn(),
    isAdmin: mockRole === 'admin',
    isRedteam: mockRole === 'redteam',
    isSoc: mockRole === 'soc',
    canEditEngagements: mockRole === 'admin' || mockRole === 'redteam',
  }),
}));

// Wrap the page in a Route so useParams gets eid and sid
function EditPage() {
  return (
    <Routes>
      <Route path="/engagements/:eid/simulations/:sid/edit" element={<SimulationFormPage />} />
    </Routes>
  );
}

function NewPage() {
  return (
    <Routes>
      <Route path="/engagements/:eid/simulations/new" element={<SimulationFormPage />} />
    </Routes>
  );
}

describe('SimulationFormPage — redteam mode (edit existing)', () => {
  let mock: MockAdapter;

  beforeEach(() => {
    mockRole = 'redteam';
    mock = new MockAdapter(apiClient);
    mock.onGet('/simulations/7').reply(200, BASE_SIM);
    mock.onGet('/engagements/42/c2-config').reply(404);
  });

  afterEach(() => {
    mock.restore();
  });

  it('renders loading state initially', () => {
    mock.onGet('/simulations/7').reply(() => new Promise(() => {}));
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });
    expect(screen.getByTestId('loading-state')).toBeInTheDocument();
  });

  it('all Red Team fields are enabled for redteam', async () => {
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByLabelText(/^Name/i)).not.toBeDisabled();
    });

    expect(screen.getByLabelText(/Description/i)).not.toBeDisabled();
    expect(screen.getByLabelText(/Commands/i)).not.toBeDisabled();
    expect(screen.getByLabelText(/Executed at/i)).not.toBeDisabled();
  });

  it('shows "Mark for review" button when status is pending', async () => {
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByRole('button', { name: /Mark for review/i })).toBeInTheDocument();
    });
  });

  it('does not show "Close" when status is pending', async () => {
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => screen.getByRole('button', { name: /Mark for review/i }));
    expect(screen.queryByRole('button', { name: /^Close$/i })).toBeNull();
  });

  it('shows "Mark for review" for in_progress status', async () => {
    mock.onGet('/simulations/7').reply(200, { ...BASE_SIM, status: 'in_progress' });
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByRole('button', { name: /Mark for review/i })).toBeInTheDocument();
    });
  });

  it('shows "Close" button when status is review_required', async () => {
    mock.onGet('/simulations/7').reply(200, { ...BASE_SIM, status: 'review_required' });
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByRole('button', { name: /^Close$/i })).toBeInTheDocument();
    });
  });

  it('shows "Delete" button for redteam', async () => {
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByRole('button', { name: /^Delete$/i })).toBeInTheDocument();
    });
  });
});

describe('SimulationFormPage — SOC role + pending (blocked)', () => {
  let mock: MockAdapter;

  beforeEach(() => {
    mockRole = 'soc';
    mock = new MockAdapter(apiClient);
    mock.onGet('/simulations/7').reply(200, BASE_SIM);
    // SOC role: useC2Config disabled (canEditRT=false), so no request expected — stub anyway
    mock.onGet('/engagements/42/c2-config').reply(404);
  });

  afterEach(() => {
    mock.restore();
  });

  it('shows the SOC blocked banner', async () => {
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByTestId('soc-blocked-banner')).toBeInTheDocument();
    });
  });

  it('SOC inputs are disabled when status is pending', async () => {
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByLabelText(/Log source/i)).toBeDisabled();
    });

    expect(screen.getByLabelText(/Incident number/i)).toBeDisabled();
  });

  it('Red Team inputs are disabled for SOC', async () => {
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByLabelText(/^Name/i)).toBeDisabled();
    });

    expect(screen.getByLabelText(/Description/i)).toBeDisabled();
  });
});

describe('SimulationFormPage — SOC role + review_required (can edit SOC fields)', () => {
  let mock: MockAdapter;

  beforeEach(() => {
    mockRole = 'soc';
    mock = new MockAdapter(apiClient);
    mock.onGet('/simulations/7').reply(200, { ...BASE_SIM, status: 'review_required' });
    mock.onGet('/engagements/42/c2-config').reply(404);
  });

  afterEach(() => {
    mock.restore();
  });

  it('SOC inputs are enabled when status is review_required', async () => {
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByLabelText(/Log source/i)).not.toBeDisabled();
    });

    expect(screen.getByLabelText(/Incident number/i)).not.toBeDisabled();
  });

  it('Red Team inputs remain disabled for SOC even when review_required', async () => {
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByLabelText(/^Name/i)).toBeDisabled();
    });
  });

  it('does not show the blocked banner when status is review_required', async () => {
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByLabelText(/Log source/i)).not.toBeDisabled();
    });

    expect(screen.queryByTestId('soc-blocked-banner')).toBeNull();
  });

  it('shows "Close" for SOC when review_required', async () => {
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });

    await waitFor(() => {
      expect(screen.getByRole('button', { name: /^Close$/i })).toBeInTheDocument();
    });
  });
});

describe('SimulationFormPage — new simulation', () => {
  let mock: MockAdapter;

  beforeEach(() => {
    mockRole = 'redteam';
    mock = new MockAdapter(apiClient);
  });

  afterEach(() => {
    mock.restore();
  });

  it('renders the new simulation form with name field', () => {
    renderWithProviders(<NewPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/new'] },
    });
    expect(screen.getByLabelText(/^Name/i)).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /Create simulation/i })).toBeInTheDocument();
  });
});

describe('SimulationFormPage — Execute via C2 button visibility', () => {
  let mock: MockAdapter;

  beforeEach(() => {
    mockRole = 'redteam';
    mock = new MockAdapter(apiClient);
    mock.onGet('/simulations/7').reply(200, BASE_SIM);
  });

  afterEach(() => {
    mock.restore();
  });

  it('shows Execute via C2 button when c2 config exists', async () => {
    mock.onGet('/engagements/42/c2-config').reply(200, {
      has_token: true,
      url: 'https://mythic.lab:7443',
      verify_tls: true,
    });
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });
    await waitFor(() => {
      expect(screen.getByTestId('c2-execute-btn')).toBeInTheDocument();
    });
  });

  it('hides Execute via C2 button when no c2 config (404)', async () => {
    mock.onGet('/engagements/42/c2-config').reply(404);
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });
    await waitFor(() => {
      expect(screen.getByLabelText(/^Name/i)).not.toBeDisabled();
    });
    expect(screen.queryByTestId('c2-execute-btn')).toBeNull();
  });

  it('hides Execute via C2 button when simulation is done', async () => {
    mock.onGet('/simulations/7').reply(200, { ...BASE_SIM, status: 'done' });
    mock.onGet('/engagements/42/c2-config').reply(200, {
      has_token: true,
      url: 'https://mythic.lab:7443',
      verify_tls: true,
    });
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });
    await waitFor(() => {
      expect(screen.getByTestId('reopen-btn')).toBeInTheDocument();
    });
    expect(screen.queryByTestId('c2-execute-btn')).toBeNull();
  });
});

describe('SimulationFormPage — C2 tasks panel visibility', () => {
  let mock: MockAdapter;

  beforeEach(() => {
    mockRole = 'redteam';
    mock = new MockAdapter(apiClient);
    mock.onGet('/simulations/7').reply(200, BASE_SIM);
  });

  afterEach(() => {
    mock.restore();
  });

  it('shows C2 tasks panel when c2 config exists (even with no tasks)', async () => {
    mock.onGet('/engagements/42/c2-config').reply(200, {
      has_token: true,
      url: 'https://mythic.lab:7443',
      verify_tls: true,
    });
    mock.onGet('/simulations/7/c2/tasks').reply(200, { tasks: [] });
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });
    await waitFor(() => {
      expect(screen.getByTestId('c2-tasks-panel')).toBeInTheDocument();
    });
  });

  it('hides C2 tasks panel when no c2 config and no tasks', async () => {
    mock.onGet('/engagements/42/c2-config').reply(404);
    mock.onGet('/simulations/7/c2/tasks').reply(200, { tasks: [] });
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });
    // Wait for page data to load then confirm no panel
    await waitFor(() => {
      expect(screen.getByLabelText(/^Name/i)).not.toBeDisabled();
    });
    expect(screen.queryByTestId('c2-tasks-panel')).toBeNull();
  });

  it('shows C2 tasks panel when tasks exist even without c2 config', async () => {
    mock.onGet('/engagements/42/c2-config').reply(404);
    mock.onGet('/simulations/7/c2/tasks').reply(200, {
      tasks: [
        {
          id: 1,
          mythic_task_display_id: 10,
          callback_display_id: 1,
          command: 'whoami',
          params: null,
          status: 'completed',
          completed: true,
          output: 'SYSTEM',
          mapping_applied: false,
          created_at: '2026-06-10T10:00:00',
          completed_at: '2026-06-10T10:00:05',
        },
      ],
    });
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });
    await waitFor(() => {
      expect(screen.getByTestId('c2-tasks-panel')).toBeInTheDocument();
    });
  });

  it('SOC role never sees C2 tasks panel', async () => {
    mockRole = 'soc';
    mock.onGet('/engagements/42/c2-config').reply(200, {
      has_token: true,
      url: 'https://mythic.lab:7443',
      verify_tls: true,
    });
    mock.onGet('/simulations/7/c2/tasks').reply(200, { tasks: [] });
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });
    await waitFor(() => {
      expect(screen.getByTestId('soc-blocked-banner')).toBeInTheDocument();
    });
    expect(screen.queryByTestId('c2-tasks-panel')).toBeNull();
  });

  it('shows Import C2 history button when c2 config exists', async () => {
    mock.onGet('/engagements/42/c2-config').reply(200, {
      has_token: true,
      url: 'https://mythic.lab:7443',
      verify_tls: true,
    });
    mock.onGet('/simulations/7/c2/tasks').reply(200, { tasks: [] });
    renderWithProviders(<EditPage />, {
      routerProps: { initialEntries: ['/engagements/42/simulations/7/edit'] },
    });
    await waitFor(() => {
      expect(screen.getByTestId('c2-import-trigger-btn')).toBeInTheDocument();
    });
  });
});
