import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ExportEngagementButton } from '@/components/ExportEngagementButton';
import { ToastViewport } from '@/components/Toast';
import { renderWithProviders } from './utils';

function ExportButtonWithToast({ engagementId }: { engagementId: number }) {
  return (
    <>
      <ExportEngagementButton engagementId={engagementId} />
      <ToastViewport />
    </>
  );
}

vi.mock('@/api/exports', () => ({
  downloadEngagementExport: vi.fn(),
}));

import { downloadEngagementExport } from '@/api/exports';
const mockDownload = downloadEngagementExport as ReturnType<typeof vi.fn>;

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('ExportEngagementButton', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

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

  it('renders Export button with chevron', () => {
    renderWithProviders(<ExportEngagementButton engagementId={1} />);
    expect(screen.getByTestId('export-btn')).toBeInTheDocument();
    expect(screen.getByTestId('export-dropdown-toggle')).toBeInTheDocument();
    expect(screen.getByText('Export')).toBeInTheDocument();
  });

  it('clicking primary opens dropdown with three formats', async () => {
    const user = userEvent.setup();
    renderWithProviders(<ExportEngagementButton engagementId={1} />);
    await user.click(screen.getByTestId('export-btn'));
    expect(screen.getByText('Markdown')).toBeInTheDocument();
    expect(screen.getByText('CSV')).toBeInTheDocument();
    expect(screen.getByText('PDF')).toBeInTheDocument();
  });

  it('clicking outside closes dropdown', async () => {
    const user = userEvent.setup();
    renderWithProviders(<ExportEngagementButton engagementId={1} />);
    await user.click(screen.getByTestId('export-btn'));
    expect(screen.getByText('Markdown')).toBeInTheDocument();
    await user.click(document.body);
    expect(screen.queryByText('Markdown')).toBeNull();
  });

  it('Escape closes dropdown', async () => {
    const user = userEvent.setup();
    renderWithProviders(<ExportEngagementButton engagementId={1} />);
    await user.click(screen.getByTestId('export-dropdown-toggle'));
    expect(screen.getByText('Markdown')).toBeInTheDocument();
    await user.keyboard('{Escape}');
    expect(screen.queryByText('Markdown')).toBeNull();
  });

  it('clicking Markdown triggers download with format=md', async () => {
    mockDownload.mockResolvedValue(undefined);
    const user = userEvent.setup();
    renderWithProviders(<ExportEngagementButton engagementId={42} />);
    await user.click(screen.getByTestId('export-btn'));
    await user.click(screen.getByTestId('export-format-md'));
    expect(mockDownload).toHaveBeenCalledWith(42, 'md');
  });

  it('clicking CSV triggers download with format=csv', async () => {
    mockDownload.mockResolvedValue(undefined);
    const user = userEvent.setup();
    renderWithProviders(<ExportEngagementButton engagementId={42} />);
    await user.click(screen.getByTestId('export-btn'));
    await user.click(screen.getByTestId('export-format-csv'));
    expect(mockDownload).toHaveBeenCalledWith(42, 'csv');
  });

  it('clicking PDF triggers download with format=pdf', async () => {
    mockDownload.mockResolvedValue(undefined);
    const user = userEvent.setup();
    renderWithProviders(<ExportEngagementButton engagementId={42} />);
    await user.click(screen.getByTestId('export-btn'));
    await user.click(screen.getByTestId('export-format-pdf'));
    expect(mockDownload).toHaveBeenCalledWith(42, 'pdf');
  });

  it('loading state disables items during in-flight', async () => {
    let resolve!: () => void;
    mockDownload.mockReturnValue(new Promise<void>((r) => { resolve = r; }));
    const user = userEvent.setup();
    renderWithProviders(<ExportEngagementButton engagementId={1} />);
    await user.click(screen.getByTestId('export-btn'));
    await user.click(screen.getByTestId('export-format-md'));
    // Items should be disabled while in-flight
    await waitFor(() => {
      expect(screen.getByTestId('export-format-csv')).toBeDisabled();
      expect(screen.getByTestId('export-format-pdf')).toBeDisabled();
    });
    resolve();
  });

  it('error response shows toast', async () => {
    mockDownload.mockRejectedValue(new Error('Export failed: 403 Forbidden'));
    const user = userEvent.setup();
    renderWithProviders(<ExportButtonWithToast engagementId={1} />);
    await user.click(screen.getByTestId('export-btn'));
    await user.click(screen.getByTestId('export-format-md'));
    await waitFor(() => {
      expect(screen.getByTestId('toast')).toBeInTheDocument();
      expect(screen.getByTestId('toast')).toHaveTextContent('Export failed: 403 Forbidden');
    });
  });
});
