import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, waitFor, fireEvent } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { RouterProvider, createRouter, createRootRoute, createRoute } from '@tanstack/react-router'
import { ChampionshipPage } from '../pages/ChampionshipPage'
import type { ChampHubDriver, ChampHubTeam, ChampionshipHub } from '../types'

vi.mock('../api', () => ({
  fetchSeasons: vi.fn(),
  fetchChampionshipHub: vi.fn(),
}))

import { fetchSeasons, fetchChampionshipHub } from '../api'

const mockFetchSeasons = vi.mocked(fetchSeasons)
const mockFetchHub = vi.mocked(fetchChampionshipHub)

function driver(over: Partial<ChampHubDriver>): ChampHubDriver {
  return {
    driver_number: 1,
    name_acronym: 'VER',
    full_name: 'Max Verstappen',
    team_name: 'Red Bull',
    team_colour: '3671c6',
    points: 200,
    position: 1,
    wins: 5,
    podiums: 8,
    poles: 4,
    form: [25, 18, 25, 15, 25],
    cumulative: [25, 43, 68, 83, 108, 200],
    teammate_wins: 9,
    teammate_losses: 1,
    ...over,
  }
}

const drivers: ChampHubDriver[] = [
  driver({ driver_number: 1, name_acronym: 'VER', team_name: 'Red Bull', points: 200, position: 1 }),
  driver({
    driver_number: 4,
    name_acronym: 'NOR',
    full_name: 'Lando Norris',
    team_name: 'McLaren',
    team_colour: 'ff8000',
    points: 160,
    position: 2,
    wins: 3,
    cumulative: [18, 36, 54, 80, 120, 160],
  }),
  driver({
    driver_number: 16,
    name_acronym: 'LEC',
    full_name: 'Charles Leclerc',
    team_name: 'Ferrari',
    team_colour: 'e8002d',
    points: 120,
    position: 3,
    wins: 1,
    cumulative: [15, 28, 40, 60, 90, 120],
  }),
]

const teams: ChampHubTeam[] = [
  { team_name: 'Red Bull', team_colour: '3671c6', points: 260, position: 1, wins: 6 },
  { team_name: 'McLaren', team_colour: 'ff8000', points: 220, position: 2, wins: 3 },
  { team_name: 'Ferrari', team_colour: 'e8002d', points: 180, position: 3, wins: 1 },
]

const hub: ChampionshipHub = {
  season: 2025,
  round: 6,
  total_rounds: 10,
  rounds_left: 4,
  last_race: 'Monaco GP',
  round_labels: ['R1', 'R2', 'R3', 'R4', 'R5', 'R6'],
  drivers,
  teams,
}

function renderPage() {
  const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } })
  const rootRoute = createRootRoute({
    component: () => (
      <QueryClientProvider client={queryClient}>
        <ChampionshipPage />
      </QueryClientProvider>
    ),
  })
  const indexRoute = createRoute({ getParentRoute: () => rootRoute, path: '/', component: ChampionshipPage })
  const router = createRouter({ routeTree: rootRoute.addChildren([indexRoute]) })
  return render(<RouterProvider router={router} />)
}

describe('ChampionshipPage', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    window.localStorage.clear()
    mockFetchSeasons.mockResolvedValue([2025])
    mockFetchHub.mockResolvedValue(hub)
  })

  it('renders the drivers view with leader and title math', async () => {
    renderPage()

    await waitFor(() => {
      expect(screen.getByTestId('championship')).toBeInTheDocument()
    })

    expect(screen.getByTestId('champ-view-drivers')).toBeInTheDocument()
    // Leader code shows in the stat rail and the table.
    expect(screen.getAllByText('VER').length).toBeGreaterThan(0)
    expect(screen.getByText('Monaco GP', { exact: false })).toBeInTheDocument()
    expect(screen.getByTestId('champ-titlemath')).toHaveTextContent('mathematically win the title')
  })

  it('switches to constructors and progression views', async () => {
    renderPage()

    await waitFor(() => expect(screen.getByTestId('championship')).toBeInTheDocument())

    fireEvent.click(screen.getByTestId('champ-tab-constructors'))
    expect(screen.getByTestId('champ-view-constructors')).toBeInTheDocument()
    expect(screen.getAllByText('Red Bull', { exact: false }).length).toBeGreaterThan(0)

    fireEvent.click(screen.getByTestId('champ-tab-progression'))
    expect(screen.getByTestId('champ-view-progression')).toBeInTheDocument()
    expect(screen.getByText('Cumulative points', { exact: false })).toBeInTheDocument()
  })

  it('switches to the simulator view and projects standings', async () => {
    renderPage()

    await waitFor(() => expect(screen.getByTestId('championship')).toBeInTheDocument())

    fireEvent.click(screen.getByTestId('champ-tab-simulator'))
    expect(screen.getByTestId('champ-view-simulator')).toBeInTheDocument()
    expect(screen.getByTestId('sim-projected')).toBeInTheDocument()
    // 4 rounds left, default scenario: VER projects to 200 + 4×25 = 300.
    expect(screen.getByText('300')).toBeInTheDocument()
  })

  it('shows the empty state when no drivers are returned', async () => {
    mockFetchHub.mockResolvedValue({ ...hub, drivers: [], teams: [] })
    renderPage()

    await waitFor(() => {
      expect(screen.getByTestId('championship-empty')).toBeInTheDocument()
    })
    expect(screen.getByText('No championship data')).toBeInTheDocument()
  })
})
