import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MockAdapter from 'axios-mock-adapter';
import { apiClient } from '@/api/client';
import { TemplatesListPage } from '@/pages/TemplatesListPage';
import { renderWithProviders } from './utils';
import type { SimulationTemplate } from '@/api/types';

const TEMPLATES: SimulationTemplate[] = [
  {
    id: 1,
    name: 'Mimikatz LSASS Dump',
    description: 'Extract NTLM hashes',
    commands: 'mimikatz.exe',
    prerequisites: 'Local admin',
    techniques: [{ id: 'T1003', name: 'OS Credential Dumping', tactics: ['credential-access'] }],
    tactics: [{ id: 'TA0006', name: 'Credential Access' }],
    created_at: '2026-05-28T00:00:00',
    updated_at: null,
    created_by: { id: 1, username: 'alice' },
  },
  {
    id: 2,
    name: 'PowerShell Empire',
    description: null,
    commands: null,
    prerequisites: null,
    techniques: [],
    tactics: [],
    created_at: '2026-05-28T01:00:00',
    updated_at: '2026-05-28T02:00:00',
    created_by: { id: 2, username: 'bob' },
  },
];

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

describe('TemplatesListPage', () => {
  let mock: MockAdapter;

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

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

  it('shows loading state initially', () => {
    mock.onGet('/templates').reply(() => new Promise(() => {}));
    renderWithProviders(<TemplatesListPage />);
    expect(screen.getByTestId('loading-state')).toBeInTheDocument();
  });

  it('shows error state on failure', async () => {
    mock.onGet('/templates').reply(500, { error: 'Server error' });
    renderWithProviders(<TemplatesListPage />);
    await waitFor(() => {
      expect(screen.getByTestId('error-state')).toBeInTheDocument();
    });
  });

  it('shows empty state when no templates', async () => {
    mock.onGet('/templates').reply(200, []);
    renderWithProviders(<TemplatesListPage />);
    await waitFor(() => {
      expect(screen.getByTestId('empty-state')).toBeInTheDocument();
    });
  });

  it('renders template list with name, MITRE count, created by', async () => {
    mock.onGet('/templates').reply(200, TEMPLATES);
    renderWithProviders(<TemplatesListPage />);
    await waitFor(() => {
      expect(screen.getByText('Mimikatz LSASS Dump')).toBeInTheDocument();
    });
    expect(screen.getByText('PowerShell Empire')).toBeInTheDocument();
    // MITRE count: techniques(1) + tactics(1) = 2 for first template
    expect(screen.getByText('2')).toBeInTheDocument();
    // Second template: 0 — shown as —
    expect(screen.getAllByText('—').length).toBeGreaterThan(0);
    expect(screen.getByText('alice')).toBeInTheDocument();
  });

  it('shows New button', async () => {
    mock.onGet('/templates').reply(200, TEMPLATES);
    renderWithProviders(<TemplatesListPage />);
    await waitFor(() => {
      expect(screen.getByText('Mimikatz LSASS Dump')).toBeInTheDocument();
    });
    expect(screen.getAllByText(/Nouveau/i).length).toBeGreaterThan(0);
  });

  it('shows Edit and Delete actions', async () => {
    mock.onGet('/templates').reply(200, TEMPLATES);
    renderWithProviders(<TemplatesListPage />);
    await waitFor(() => {
      expect(screen.getByText('Mimikatz LSASS Dump')).toBeInTheDocument();
    });
    expect(screen.getAllByText('Modifier').length).toBe(2);
    expect(screen.getAllByText('Supprimer').length).toBe(2);
  });

  it('calls delete endpoint on confirm', async () => {
    mock.onGet('/templates').reply(200, TEMPLATES);
    mock.onDelete('/templates/1').reply(204);
    // After delete, refetch returns updated list
    mock.onGet('/templates').reply(200, [TEMPLATES[1]]);

    const user = userEvent.setup();
    const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(true);

    renderWithProviders(<TemplatesListPage />);
    await waitFor(() => {
      expect(screen.getAllByText('Supprimer')[0]).toBeInTheDocument();
    });

    const deleteButtons = screen.getAllByText('Supprimer');
    await user.click(deleteButtons[0]);

    await waitFor(() => {
      expect(mock.history.delete.length).toBe(1);
    });
    confirmSpy.mockRestore();
  });
});
