import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { ThemeProvider, useTheme } from './ThemeContext'

function ThemeConsumer() {
  const { theme, resolvedTheme, setTheme, toggleTheme } = useTheme()
  return (
    <div>
      <div data-testid="theme">{theme}</div>
      <div data-testid="resolved">{resolvedTheme}</div>
      <button onClick={() => setTheme('dark')}>set dark</button>
      <button onClick={toggleTheme}>toggle</button>
    </div>
  )
}

describe('ThemeProvider', () => {
  beforeEach(() => {
    localStorage.clear()
  })

  it('loads theme from localStorage and applies resolved theme', () => {
    localStorage.setItem('mp-theme', 'dark')
    const matchMediaMock = vi.fn().mockReturnValue({
      matches: false,
      addEventListener: vi.fn(),
      removeEventListener: vi.fn()
    })
    vi.stubGlobal('matchMedia', matchMediaMock)

    render(
      <ThemeProvider>
        <ThemeConsumer />
      </ThemeProvider>
    )

    expect(screen.getByTestId('theme')).toHaveTextContent('dark')
    expect(screen.getByTestId('resolved')).toHaveTextContent('dark')
    expect(document.documentElement.classList.contains('dark')).toBe(true)
    expect(document.documentElement.getAttribute('data-theme')).toBe('dark')
  })

  it('resolves system theme when set to system', async () => {
    const matchMediaMock = vi.fn().mockReturnValue({
      matches: true,
      addEventListener: vi.fn(),
      removeEventListener: vi.fn()
    })
    vi.stubGlobal('matchMedia', matchMediaMock)

    render(
      <ThemeProvider>
        <ThemeConsumer />
      </ThemeProvider>
    )

    expect(screen.getByTestId('theme')).toHaveTextContent('system')
    expect(screen.getByTestId('resolved')).toHaveTextContent('dark')
    expect(document.documentElement.classList.contains('dark')).toBe(true)

    const user = userEvent.setup()
    await user.click(screen.getByRole('button', { name: /set dark/i }))
    expect(localStorage.getItem('mp-theme')).toBe('dark')
  })

  it('toggles between light and dark', async () => {
    const matchMediaMock = vi.fn().mockReturnValue({
      matches: false,
      addEventListener: vi.fn(),
      removeEventListener: vi.fn()
    })
    vi.stubGlobal('matchMedia', matchMediaMock)

    render(
      <ThemeProvider>
        <ThemeConsumer />
      </ThemeProvider>
    )

    const user = userEvent.setup()
    expect(screen.getByTestId('resolved')).toHaveTextContent('light')

    await user.click(screen.getByRole('button', { name: /toggle/i }))
    await waitFor(() => expect(screen.getByTestId('resolved')).toHaveTextContent('dark'))
    expect(document.documentElement.classList.contains('dark')).toBe(true)
  })

  it('throws when useTheme is used outside provider', () => {
    const ConsoleError = console.error
    console.error = vi.fn()
    expect(() => render(<ThemeConsumer />)).toThrow('useTheme must be used within ThemeProvider')
    console.error = ConsoleError
  })
})
