import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { screen, waitFor, fireEvent } from '@testing-library/react';
import MockAdapter from 'axios-mock-adapter';
import { apiClient } from '@/api/client';
import { C2ConfigCard } from '@/components/C2ConfigCard';
import { renderWithProviders } from '../utils';

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,
  }),
}));

let mock: MockAdapter;

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

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

describe('C2ConfigCard — no config (404)', () => {
  it('renders the card with empty fields when no config exists', async () => {
    mock.onGet('/engagements/1/c2-config').reply(404);
    renderWithProviders(<C2ConfigCard engagementId={1} />);
    // Wait for loading to finish — query resolves to null on 404
    await waitFor(() => {
      expect(screen.getByTestId('c2-url-input')).toBeInTheDocument();
    });
    expect(screen.getByTestId('c2-token-input')).toBeInTheDocument();
    expect(screen.getByTestId('c2-verify-tls')).toBeInTheDocument();
    expect(screen.getByTestId('c2-save-btn')).toBeInTheDocument();
    // Delete button only shown when has_token
    expect(screen.queryByTestId('c2-delete-btn')).toBeNull();
  });
});

describe('C2ConfigCard — with config (has_token=true)', () => {
  beforeEach(() => {
    mock.onGet('/engagements/1/c2-config').reply(200, {
      has_token: true,
      url: 'https://mythic.lab:7443',
      verify_tls: true,
    });
  });

  it('shows Replace token affordance when has_token=true', async () => {
    renderWithProviders(<C2ConfigCard engagementId={1} />);
    await waitFor(() => {
      expect(screen.getByText('Replace token')).toBeInTheDocument();
    });
    // Token input shows placeholder bullets (readOnly)
    const tokenInput = screen.getByTestId('c2-token-input') as HTMLInputElement;
    expect(tokenInput.readOnly).toBe(true);
    expect(tokenInput.placeholder).toBe('••••••••');
  });

  it('shows Delete configuration button when has_token=true', async () => {
    renderWithProviders(<C2ConfigCard engagementId={1} />);
    await waitFor(() => {
      expect(screen.getByTestId('c2-delete-btn')).toBeInTheDocument();
    });
  });

  it('clicking Replace token makes input editable', async () => {
    renderWithProviders(<C2ConfigCard engagementId={1} />);
    await waitFor(() => {
      expect(screen.getByText('Replace token')).toBeInTheDocument();
    });
    fireEvent.click(screen.getByText('Replace token'));
    await waitFor(() => {
      const tokenInput = screen.getByTestId('c2-token-input') as HTMLInputElement;
      expect(tokenInput.readOnly).toBeFalsy();
    });
  });

  it('Test connection button is enabled when config exists', async () => {
    renderWithProviders(<C2ConfigCard engagementId={1} />);
    await waitFor(() => {
      expect(screen.getByTestId('c2-test-btn')).not.toBeDisabled();
    });
  });

  it('shows Connected on successful test', async () => {
    mock.onPost('/engagements/1/c2-config/test').reply(200, { ok: true, error: null });
    renderWithProviders(<C2ConfigCard engagementId={1} />);
    await waitFor(() => {
      expect(screen.getByTestId('c2-test-btn')).not.toBeDisabled();
    });
    fireEvent.click(screen.getByTestId('c2-test-btn'));
    await waitFor(() => {
      expect(screen.getByText('Connected')).toBeInTheDocument();
    });
  });

  it('shows error message on failed test', async () => {
    mock
      .onPost('/engagements/1/c2-config/test')
      .reply(200, { ok: false, error: 'Connection refused' });
    renderWithProviders(<C2ConfigCard engagementId={1} />);
    await waitFor(() => {
      expect(screen.getByTestId('c2-test-btn')).not.toBeDisabled();
    });
    fireEvent.click(screen.getByTestId('c2-test-btn'));
    await waitFor(() => {
      expect(screen.getByText('Connection refused')).toBeInTheDocument();
    });
  });
});

describe('C2ConfigCard — 503 disabled state', () => {
  it('shows 503 banner and disables all inputs', async () => {
    mock.onGet('/engagements/1/c2-config').reply(503);
    renderWithProviders(<C2ConfigCard engagementId={1} />);
    await waitFor(() => {
      expect(
        screen.getByText(/C2 features are disabled/i),
      ).toBeInTheDocument();
    });
    expect(screen.getByTestId('c2-save-btn')).toBeDisabled();
    expect(screen.getByTestId('c2-url-input')).toBeDisabled();
    expect(screen.getByTestId('c2-token-input')).toBeDisabled();
    expect(screen.getByTestId('c2-verify-tls')).toBeDisabled();
  });
});
