import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { render, screen, fireEvent, waitFor, cleanup } from '@testing-library/react'
import Home from './page'

global.fetch = vi.fn()

const mockFetch = vi.mocked(global.fetch)

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

  afterEach(() => {
    cleanup()
  })

  it('renders the main heading', () => {
    render(<Home />)
    expect(screen.getByText('Downlink')).toBeInTheDocument()
  })

  it('renders the URL input', () => {
    render(<Home />)
    const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...')
    expect(inputs.length).toBeGreaterThanOrEqual(1)
  })

  it('renders the Fetch button', () => {
    render(<Home />)
    const buttons = screen.getAllByRole('button', { name: /fetch/i })
    expect(buttons.length).toBeGreaterThanOrEqual(1)
  })

  it('shows error for empty URL on fetch', async () => {
    render(<Home />)
    
    const fetchButtons = screen.getAllByRole('button', { name: /fetch/i })
    fireEvent.click(fetchButtons[0])

    await waitFor(() => {
      expect(screen.getByText('Please enter a YouTube URL')).toBeInTheDocument()
    })
  })

  it('shows error for invalid YouTube URL', async () => {
    render(<Home />)
    
    const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...')
    fireEvent.change(inputs[0], { target: { value: 'https://vimeo.com/123' } })
    
    const fetchButtons = screen.getAllByRole('button', { name: /fetch/i })
    fireEvent.click(fetchButtons[0])

    await waitFor(() => {
      expect(screen.getByText('Please enter a valid YouTube URL')).toBeInTheDocument()
    })
  })

  it('fetches video info for valid URL', async () => {
    const mockVideoInfo = {
      title: 'Test Video',
      duration: 180,
      thumbnail: 'https://example.com/thumb.jpg',
    }

    mockFetch.mockResolvedValueOnce({
      json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }),
    } as Response)

    render(<Home />)
    
    const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...')
    fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } })
    
    const fetchButtons = screen.getAllByRole('button', { name: /fetch/i })
    fireEvent.click(fetchButtons[0])

    await waitFor(() => {
      expect(screen.getByText('Test Video')).toBeInTheDocument()
    })

    expect(mockFetch).toHaveBeenCalledWith('/api/info', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ url: 'https://youtube.com/watch?v=dQw4w9WgXcQ' }),
    })
  })

  it('displays video duration after fetch', async () => {
    const mockVideoInfo = {
      title: 'Test Video',
      duration: 125,
      thumbnail: 'https://example.com/thumb.jpg',
    }

    mockFetch.mockResolvedValueOnce({
      json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }),
    } as Response)

    render(<Home />)
    
    const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...')
    fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } })
    
    const fetchButtons = screen.getAllByRole('button', { name: /fetch/i })
    fireEvent.click(fetchButtons[0])

    await waitFor(() => {
      expect(screen.getByText('2:05')).toBeInTheDocument()
    })
  })

  it('shows download options after fetching video info', async () => {
    const mockVideoInfo = {
      title: 'Test Video',
      duration: 180,
      thumbnail: 'https://example.com/thumb.jpg',
    }

    mockFetch.mockResolvedValueOnce({
      json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }),
    } as Response)

    render(<Home />)
    
    const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...')
    fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } })
    
    const fetchButtons = screen.getAllByRole('button', { name: /fetch/i })
    fireEvent.click(fetchButtons[0])

    await waitFor(() => {
      expect(screen.getByText('Download Options')).toBeInTheDocument()
    })
  })

  it('handles API error response', async () => {
    mockFetch.mockResolvedValueOnce({
      json: () => Promise.resolve({ success: false, error: 'Video not found' }),
    } as Response)

    render(<Home />)
    
    const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...')
    fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } })
    
    const fetchButtons = screen.getAllByRole('button', { name: /fetch/i })
    fireEvent.click(fetchButtons[0])

    await waitFor(() => {
      expect(screen.getByText('Video not found')).toBeInTheDocument()
    })
  })

  it('handles fetch network error', async () => {
    mockFetch.mockRejectedValueOnce(new Error('Network error'))

    render(<Home />)
    
    const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...')
    fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } })
    
    const fetchButtons = screen.getAllByRole('button', { name: /fetch/i })
    fireEvent.click(fetchButtons[0])

    await waitFor(() => {
      expect(screen.getByText('Network error')).toBeInTheDocument()
    })
  })

  it('allows switching between video and audio format types', async () => {
    const mockVideoInfo = {
      title: 'Test Video',
      duration: 180,
      thumbnail: 'https://example.com/thumb.jpg',
    }

    mockFetch.mockResolvedValueOnce({
      json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }),
    } as Response)

    render(<Home />)
    
    const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...')
    fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } })
    
    const fetchButtons = screen.getAllByRole('button', { name: /fetch/i })
    fireEvent.click(fetchButtons[0])

    await waitFor(() => {
      expect(screen.getByText('Download Options')).toBeInTheDocument()
    })

    const audioButton = screen.getByRole('button', { name: /audio/i })
    fireEvent.click(audioButton)

    expect(screen.getByText('Audio Format')).toBeInTheDocument()
  })

  it('triggers download on button click', async () => {
    const mockVideoInfo = {
      title: 'Test Video',
      duration: 180,
      thumbnail: 'https://example.com/thumb.jpg',
    }

    mockFetch
      .mockResolvedValueOnce({
        json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }),
      } as Response)
      .mockResolvedValueOnce({
        json: () => Promise.resolve({
          success: true,
          downloadUrl: '/downloads/test.mp4',
          filename: 'test.mp4',
        }),
      } as Response)

    render(<Home />)
    
    const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...')
    fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } })
    
    const fetchButtons = screen.getAllByRole('button', { name: /fetch/i })
    fireEvent.click(fetchButtons[0])

    await waitFor(() => {
      expect(screen.getByText('Download Options')).toBeInTheDocument()
    })

    const downloadButton = screen.getByRole('button', { name: /download mp4/i })
    fireEvent.click(downloadButton)

    await waitFor(() => {
      expect(mockFetch).toHaveBeenCalledTimes(2)
    })

    expect(mockFetch).toHaveBeenLastCalledWith('/api/download', expect.objectContaining({
      method: 'POST',
    }))
  })

  it('shows success message after download completes', async () => {
    const mockVideoInfo = {
      title: 'Test Video',
      duration: 180,
      thumbnail: 'https://example.com/thumb.jpg',
    }

    mockFetch
      .mockResolvedValueOnce({
        json: () => Promise.resolve({ success: true, videoInfo: mockVideoInfo }),
      } as Response)
      .mockResolvedValueOnce({
        json: () => Promise.resolve({
          success: true,
          downloadUrl: '/downloads/test.mp4',
          filename: 'test.mp4',
        }),
      } as Response)

    render(<Home />)
    
    const inputs = screen.getAllByPlaceholderText('Paste YouTube URL here...')
    fireEvent.change(inputs[0], { target: { value: 'https://youtube.com/watch?v=dQw4w9WgXcQ' } })
    
    const fetchButtons = screen.getAllByRole('button', { name: /fetch/i })
    fireEvent.click(fetchButtons[0])

    await waitFor(() => {
      expect(screen.getByText('Download Options')).toBeInTheDocument()
    })

    fireEvent.click(screen.getByRole('button', { name: /download mp4/i }))

    await waitFor(() => {
      expect(screen.getByText('Ready to Download')).toBeInTheDocument()
    })
  })
})
