import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import { QueryClientProvider } from '@tanstack/react-query';
import { queryClient } from '../../src/lib/queryClient';
import Games from '../../src/routes/games';
import * as useGamesModule from '../../src/hooks/useGames';

// Mock the useGames hooks
vi.spyOn(useGamesModule, 'useGames');
vi.spyOn(useGamesModule, 'useCreateGame');
vi.spyOn(useGamesModule, 'useUpdateGame');
vi.spyOn(useGamesModule, 'useDeleteGame');

const mockGames = [
  {
    id: '1',
    title: 'The Legend of Zelda',
    slug: 'zelda-game',
    createdAt: '2026-01-01T00:00:00Z',
    updatedAt: '2026-01-01T00:00:00Z',
    description: null,
  },
  {
    id: '2',
    title: 'Super Mario Bros',
    slug: 'mario-game',
    createdAt: '2026-01-02T00:00:00Z',
    updatedAt: '2026-01-02T00:00:00Z',
    description: null,
  },
];

describe('Games Page', () => {
  beforeEach(() => {
    vi.clearAllMocks();

    // Default mocks
    vi.mocked(useGamesModule.useGames).mockReturnValue({
      data: mockGames,
      isLoading: false,
      error: null,
    } as any);

    vi.mocked(useGamesModule.useCreateGame).mockReturnValue({
      mutateAsync: vi.fn(),
      isPending: false,
    } as any);

    vi.mocked(useGamesModule.useUpdateGame).mockReturnValue({
      mutateAsync: vi.fn(),
      isPending: false,
    } as any);

    vi.mocked(useGamesModule.useDeleteGame).mockReturnValue({
      mutateAsync: vi.fn(),
      isPending: false,
    } as any);
  });

  it('should render empty state when no games', () => {
    vi.mocked(useGamesModule.useGames).mockReturnValue({
      data: [],
      isLoading: false,
      error: null,
    } as any);

    render(
      <QueryClientProvider client={queryClient}>
        <Games />
      </QueryClientProvider>
    );

    expect(screen.getByText(/no games found/i)).toBeInTheDocument();
  });

  it('should render loading state', () => {
    vi.mocked(useGamesModule.useGames).mockReturnValue({
      data: undefined,
      isLoading: true,
      error: null,
    } as any);

    render(
      <QueryClientProvider client={queryClient}>
        <Games />
      </QueryClientProvider>
    );

    expect(screen.getByText(/loading games/i)).toBeInTheDocument();
  });

  it('should render error state', () => {
    const error = new Error('Failed to fetch');
    vi.mocked(useGamesModule.useGames).mockReturnValue({
      data: undefined,
      isLoading: false,
      error,
    } as any);

    render(
      <QueryClientProvider client={queryClient}>
        <Games />
      </QueryClientProvider>
    );

    expect(screen.getByText(/error/i)).toBeInTheDocument();
    expect(screen.getByText(/failed to fetch/i)).toBeInTheDocument();
  });

  it('should render table with games', () => {
    render(
      <QueryClientProvider client={queryClient}>
        <Games />
      </QueryClientProvider>
    );

    expect(screen.getByText('The Legend of Zelda')).toBeInTheDocument();
    expect(screen.getByText('Super Mario Bros')).toBeInTheDocument();
  });

  it('should render "Add Game" button', () => {
    render(
      <QueryClientProvider client={queryClient}>
        <Games />
      </QueryClientProvider>
    );

    expect(screen.getByRole('button', { name: /add game/i })).toBeInTheDocument();
  });

  it('should open form when "Add Game" is clicked', async () => {
    const user = await userEvent.setup();

    render(
      <QueryClientProvider client={queryClient}>
        <Games />
      </QueryClientProvider>
    );

    const addButton = screen.getByRole('button', { name: /add game/i });
    await user.click(addButton);

    await waitFor(() => {
      expect(screen.getByText(/create game/i)).toBeInTheDocument();
    });
  });

  it('should open form for editing when edit button is clicked', async () => {
    const user = await userEvent.setup();

    render(
      <QueryClientProvider client={queryClient}>
        <Games />
      </QueryClientProvider>
    );

    const editButtons = screen.getAllByRole('button', { name: /edit/i });
    await user.click(editButtons[0]);

    await waitFor(() => {
      expect(screen.getByText(/edit game/i)).toBeInTheDocument();
    });
  });

  it('should show delete confirmation when delete is clicked', async () => {
    const user = await userEvent.setup();

    render(
      <QueryClientProvider client={queryClient}>
        <Games />
      </QueryClientProvider>
    );

    const deleteButtons = screen.getAllByRole('button', { name: /delete/i });
    await user.click(deleteButtons[0]);

    await waitFor(() => {
      expect(screen.getByRole('button', { name: /confirm/i })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
    });
  });

  it('should call delete mutation when confirmed', async () => {
    const user = await userEvent.setup();
    const deleteAsync = vi.fn().mockResolvedValue(undefined);

    vi.mocked(useGamesModule.useDeleteGame).mockReturnValue({
      mutateAsync: deleteAsync,
      isPending: false,
    } as any);

    render(
      <QueryClientProvider client={queryClient}>
        <Games />
      </QueryClientProvider>
    );

    const deleteButtons = screen.getAllByRole('button', { name: /delete/i });
    await user.click(deleteButtons[0]);

    const confirmButton = await screen.findByRole('button', { name: /confirm/i });
    await user.click(confirmButton);

    await waitFor(() => {
      expect(deleteAsync).toHaveBeenCalledWith('1');
    });
  });

  it('should display table headers', () => {
    render(
      <QueryClientProvider client={queryClient}>
        <Games />
      </QueryClientProvider>
    );

    expect(screen.getByText('Title')).toBeInTheDocument();
    expect(screen.getByText('Slug')).toBeInTheDocument();
    expect(screen.getByText('Created')).toBeInTheDocument();
    expect(screen.getByText('Actions')).toBeInTheDocument();
  });
});
