import { describe, it, expect, vi, beforeEach, MockedFunction } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import EditTournamentForm from '@/components/EditTournamentForm'

// Mock next/navigation
vi.mock('next/navigation', () => ({
  useRouter: () => ({
    push: vi.fn(),
  }),
}))

// Mock next/link
vi.mock('next/link', () => ({
  default: ({ children, href }: { children: React.ReactNode; href: string }) => (
    <a href={href}>{children}</a>
  ),
}))

// Mock fetch
const mockFetch = vi.fn()
global.fetch = mockFetch as MockedFunction<typeof global.fetch>

const mockTournament = {
  id: 1,
  event_id: null,
  name: 'Test Tournament',
  description: 'A test tournament',
  eventDate: new Date('2024-01-15'),
  eventType: 'tournament',
  format: 'round_robin',
  status: 'planned',
  maxParticipants: 16,
  ownerId: null,
  targetScore: null,
  allowTies: false,
  createdAt: new Date(),
  updatedAt: new Date(),
}

describe('EditTournamentForm', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  it('renders form with initial values', () => {
    render(<EditTournamentForm tournament={mockTournament} />)

    expect(screen.getByLabelText('Tournament Name')).toHaveValue('Test Tournament')
    expect(screen.getByLabelText('Description')).toHaveValue('A test tournament')
    expect(screen.getByLabelText('Date')).toHaveValue('2024-01-15')
    expect(screen.getByLabelText('Event Type')).toHaveValue('tournament')
    expect(screen.getByLabelText('Format')).toHaveValue('round_robin')
    expect(screen.getByLabelText('Status')).toHaveValue('planned')
    expect(screen.getByLabelText('Max Participants (optional)')).toHaveValue(16)
  })

  it('updates form values on change', async () => {
    const user = userEvent.setup()
    render(<EditTournamentForm tournament={mockTournament} />)

    const nameInput = screen.getByLabelText('Tournament Name')
    await user.clear(nameInput)
    await user.type(nameInput, 'Updated Tournament')

    expect(nameInput).toHaveValue('Updated Tournament')
  })

  it('submits form with updated data', async () => {
    const user = userEvent.setup()
    mockFetch.mockResolvedValueOnce({
      ok: true,
      json: async () => ({ success: true }),
    } as Response)

    render(<EditTournamentForm tournament={mockTournament} />)

    const nameInput = screen.getByLabelText('Tournament Name')
    await user.clear(nameInput)
    await user.type(nameInput, 'Updated Tournament')

    const submitButton = screen.getByText('Save Changes')
    await user.click(submitButton)

    await waitFor(() => {
      expect(mockFetch).toHaveBeenCalledWith(
        '/api/tournaments/1',
        expect.objectContaining({
          method: 'PUT',
          body: expect.stringContaining('Updated Tournament'),
        })
      )
    })
  })

  it('shows error message on failed submission', async () => {
    const user = userEvent.setup()
    mockFetch.mockResolvedValueOnce({
      ok: false,
      json: async () => ({ error: 'Failed to update tournament' }),
    } as Response)

    render(<EditTournamentForm tournament={mockTournament} />)

    const submitButton = screen.getByText('Save Changes')
    await user.click(submitButton)

    await waitFor(() => {
      expect(screen.getByText('Failed to update tournament')).toBeInTheDocument()
    })
  })

  it('disables submit button while loading', async () => {
    const user = userEvent.setup()
    mockFetch.mockImplementation(
      () =>
        new Promise((resolve) => {
          setTimeout(() => {
            resolve({
              ok: true,
              json: async () => ({ success: true }),
            } as Response)
          }, 100)
        })
    )

    render(<EditTournamentForm tournament={mockTournament} />)

    const submitButton = screen.getByText('Save Changes')
    await user.click(submitButton)

    expect(submitButton).toBeDisabled()
    expect(submitButton).toHaveTextContent('Saving...')
  })
})
