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 { TemplatePickerModal } from '@/components/TemplatePickerModal';
import { renderWithProviders } from './utils';
import type { SimulationTemplate } from '@/api/types';

const TEMPLATES: SimulationTemplate[] = [
  {
    id: 1,
    name: 'Mimikatz LSASS Dump',
    description: null,
    commands: null,
    prerequisites: null,
    techniques: [{ id: 'T1003', name: 'OS Credential Dumping', tactics: [] }],
    tactics: [],
    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: [{ id: 'TA0002', name: 'Execution' }],
    created_at: '2026-05-28T01:00:00',
    updated_at: null,
    created_by: { id: 1, username: 'alice' },
  },
];

const onClose = vi.fn();
const onInstantiated = vi.fn();
const onSelectTemplate = vi.fn();

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

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

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

  it('shows loading state while fetching', () => {
    mock.onGet('/templates').reply(() => new Promise(() => {}));
    renderWithProviders(
      <TemplatePickerModal
        engagementId={1}
        onClose={onClose}
        onInstantiated={onInstantiated}
        onSelectTemplate={onSelectTemplate}
      />
    );
    expect(screen.getByTestId('loading-state')).toBeInTheDocument();
  });

  it('shows empty state when no templates', async () => {
    mock.onGet('/templates').reply(200, []);
    renderWithProviders(
      <TemplatePickerModal
        engagementId={1}
        onClose={onClose}
        onInstantiated={onInstantiated}
        onSelectTemplate={onSelectTemplate}
      />
    );
    await waitFor(() => {
      expect(screen.getByTestId('empty-state')).toBeInTheDocument();
    });
    expect(screen.getByText(/Aucun template disponible/i)).toBeInTheDocument();
  });

  it('lists templates with name and MITRE count', async () => {
    mock.onGet('/templates').reply(200, TEMPLATES);
    renderWithProviders(
      <TemplatePickerModal
        engagementId={1}
        onClose={onClose}
        onInstantiated={onInstantiated}
        onSelectTemplate={onSelectTemplate}
      />
    );
    await waitFor(() => {
      expect(screen.getByTestId('template-picker-table')).toBeInTheDocument();
    });
    expect(screen.getByText('Mimikatz LSASS Dump')).toBeInTheDocument();
    expect(screen.getByText('PowerShell Empire')).toBeInTheDocument();
    // T1(1 tech) + 0 tactics = 1 for first, 0 tech + 1 tactic = 1 for second
    expect(screen.getAllByText('1').length).toBe(2);
  });

  it('calls onSelectTemplate when a template row is clicked', async () => {
    mock.onGet('/templates').reply(200, TEMPLATES);
    const user = userEvent.setup();
    renderWithProviders(
      <TemplatePickerModal
        engagementId={1}
        onClose={onClose}
        onInstantiated={onInstantiated}
        onSelectTemplate={onSelectTemplate}
      />
    );
    await waitFor(() => {
      expect(screen.getByText('Mimikatz LSASS Dump')).toBeInTheDocument();
    });
    await user.click(screen.getByTestId('template-row-1'));
    expect(onSelectTemplate).toHaveBeenCalledWith(TEMPLATES[0]);
  });

  it('calls onClose when Cancel is clicked', async () => {
    mock.onGet('/templates').reply(200, TEMPLATES);
    const user = userEvent.setup();
    renderWithProviders(
      <TemplatePickerModal
        engagementId={1}
        onClose={onClose}
        onInstantiated={onInstantiated}
        onSelectTemplate={onSelectTemplate}
      />
    );
    await waitFor(() => {
      expect(screen.getByText('Annuler')).toBeInTheDocument();
    });
    await user.click(screen.getByText('Annuler'));
    expect(onClose).toHaveBeenCalledOnce();
  });

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