import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import ApiTokensSection from '../ApiTokensSection';

// Mock react-i18next
vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string, defaultValue?: string) => defaultValue || key,
  }),
}));

// Mock the hooks
const mockTokens = [
  {
    id: '1',
    name: 'Test Token',
    key_prefix: 'abc123',
    scopes: ['read:appointments', 'write:appointments'],
    is_active: true,
    created_at: '2024-01-01T00:00:00Z',
    last_used_at: '2024-01-02T00:00:00Z',
    expires_at: null,
    created_by: { full_name: 'John Doe', username: 'john' },
  },
  {
    id: '2',
    name: 'Revoked Token',
    key_prefix: 'xyz789',
    scopes: ['read:resources'],
    is_active: false,
    created_at: '2024-01-01T00:00:00Z',
    last_used_at: null,
    expires_at: null,
    created_by: null,
  },
];

const mockUseApiTokens = vi.fn();
const mockUseCreateApiToken = vi.fn();
const mockUseRevokeApiToken = vi.fn();
const mockUseUpdateApiToken = vi.fn();

vi.mock('../../hooks/useApiTokens', () => ({
  useApiTokens: () => mockUseApiTokens(),
  useCreateApiToken: () => mockUseCreateApiToken(),
  useRevokeApiToken: () => mockUseRevokeApiToken(),
  useUpdateApiToken: () => mockUseUpdateApiToken(),
  API_SCOPES: [
    { value: 'read:appointments', label: 'Read Appointments', description: 'View appointments' },
    { value: 'write:appointments', label: 'Write Appointments', description: 'Create/edit appointments' },
    { value: 'read:resources', label: 'Read Resources', description: 'View resources' },
  ],
  SCOPE_PRESETS: {
    read_only: { label: 'Read Only', description: 'View data only', scopes: ['read:appointments', 'read:resources'] },
    read_write: { label: 'Read & Write', description: 'Full access', scopes: ['read:appointments', 'write:appointments', 'read:resources'] },
    custom: { label: 'Custom', description: 'Select individual permissions', scopes: [] },
  },
}));

const createWrapper = () => {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
    },
  });
  return ({ children }: { children: React.ReactNode }) => (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  );
};

describe('ApiTokensSection', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockUseCreateApiToken.mockReturnValue({ mutateAsync: vi.fn(), isPending: false });
    mockUseRevokeApiToken.mockReturnValue({ mutateAsync: vi.fn(), isPending: false });
    mockUseUpdateApiToken.mockReturnValue({ mutateAsync: vi.fn(), isPending: false });
  });

  it('renders loading state', () => {
    mockUseApiTokens.mockReturnValue({ data: undefined, isLoading: true, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(document.querySelector('.animate-spin')).toBeInTheDocument();
  });

  it('renders error state', () => {
    mockUseApiTokens.mockReturnValue({ data: undefined, isLoading: false, error: new Error('Failed') });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText(/Failed to load API tokens/)).toBeInTheDocument();
  });

  it('renders empty state when no tokens', () => {
    mockUseApiTokens.mockReturnValue({ data: [], isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText('No API tokens yet')).toBeInTheDocument();
  });

  it('renders tokens list', () => {
    mockUseApiTokens.mockReturnValue({ data: mockTokens, isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText('Test Token')).toBeInTheDocument();
    expect(screen.getByText('Revoked Token')).toBeInTheDocument();
  });

  it('renders section title', () => {
    mockUseApiTokens.mockReturnValue({ data: [], isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText('API Tokens')).toBeInTheDocument();
  });

  it('renders New Token button', () => {
    mockUseApiTokens.mockReturnValue({ data: [], isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText('New Token')).toBeInTheDocument();
  });

  it('renders API Docs link', () => {
    mockUseApiTokens.mockReturnValue({ data: [], isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText('API Docs')).toBeInTheDocument();
  });

  it('opens new token modal when button clicked', () => {
    mockUseApiTokens.mockReturnValue({ data: mockTokens, isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    fireEvent.click(screen.getByText('New Token'));
    // Modal title should appear
    expect(screen.getByRole('heading', { name: 'Create API Token' })).toBeInTheDocument();
  });

  it('shows active tokens count', () => {
    mockUseApiTokens.mockReturnValue({ data: mockTokens, isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText(/Active Tokens \(1\)/)).toBeInTheDocument();
  });

  it('shows revoked tokens count', () => {
    mockUseApiTokens.mockReturnValue({ data: mockTokens, isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText(/Revoked Tokens \(1\)/)).toBeInTheDocument();
  });

  it('shows token key prefix', () => {
    mockUseApiTokens.mockReturnValue({ data: mockTokens, isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText(/abc123••••••••/)).toBeInTheDocument();
  });

  it('shows revoked badge for inactive tokens', () => {
    mockUseApiTokens.mockReturnValue({ data: mockTokens, isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText('Revoked')).toBeInTheDocument();
  });

  it('renders description text', () => {
    mockUseApiTokens.mockReturnValue({ data: [], isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText(/Create and manage API tokens/)).toBeInTheDocument();
  });

  it('renders create button in empty state', () => {
    mockUseApiTokens.mockReturnValue({ data: [], isLoading: false, error: null });
    render(<ApiTokensSection />, { wrapper: createWrapper() });
    expect(screen.getByText('Create API Token')).toBeInTheDocument();
  });
});
