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

import WegZurAuszeichnungSection from '@/spa/components/WegZurAuszeichnungSection'
import {
  getActiveTimelineStep,
  getTimelineScrollBehavior,
  getTimelineStepScrollLeft,
} from '@/spa/components/ui/process-timeline'

vi.mock('@/spa/hooks/useIsMobile', () => ({
  useIsMobile: () => false,
}))

let reduceMotion = false

describe('participation timeline', () => {
  beforeEach(() => {
    reduceMotion = false
    Object.defineProperty(window, 'matchMedia', {
      configurable: true,
      value: vi.fn().mockImplementation((query: string) => ({
        addEventListener: vi.fn(),
        matches: query === '(prefers-reduced-motion: reduce)' && reduceMotion,
        media: query,
        removeEventListener: vi.fn(),
      })),
    })
  })

  afterEach(() => cleanup())

  it('maps the real horizontal scroll range to deterministic steps', () => {
    expect(getActiveTimelineStep(0, 600, 4)).toBe(0)
    expect(getActiveTimelineStep(200, 600, 4)).toBe(1)
    expect(getActiveTimelineStep(400, 600, 4)).toBe(2)
    expect(getActiveTimelineStep(600, 600, 4)).toBe(3)
    expect(getTimelineStepScrollLeft(2, 600, 4)).toBe(400)
    expect(getTimelineStepScrollLeft(99, 600, 4)).toBe(600)
  })

  it('updates progress from native track scroll state', () => {
    render(<WegZurAuszeichnungSection />)
    const track = screen.getByTestId('timeline-track')
    Object.defineProperties(track, {
      clientWidth: { configurable: true, value: 400 },
      scrollLeft: { configurable: true, value: 400, writable: true },
      scrollWidth: { configurable: true, value: 1000 },
    })

    fireEvent.scroll(track)

    expect(screen.getByTestId('timeline-progress-label').textContent).toContain('03 / 04')
    expect(screen.getByTestId('timeline-progress').style.width).toBe('75%')
    expect(screen.getAllByTestId(/timeline-step-/)).toHaveLength(4)
  })

  it('uses immediate scrolling in reduced-motion mode while keeping controls operable', () => {
    reduceMotion = true
    render(<WegZurAuszeichnungSection />)
    const track = screen.getByTestId('timeline-track')
    const scrollTo = vi.fn()
    Object.defineProperties(track, {
      clientWidth: { configurable: true, value: 400 },
      scrollTo: { configurable: true, value: scrollTo },
      scrollWidth: { configurable: true, value: 1000 },
    })

    fireEvent.click(screen.getByRole('button', { name: 'Nächster Schritt' }))

    expect(getTimelineScrollBehavior(true)).toBe('auto')
    expect(scrollTo).toHaveBeenCalledWith({ behavior: 'auto', left: 200 })
    expect(screen.getByTestId('timeline-progress-label').textContent).toContain('02 / 04')
  })

  it('supports direct keyboard navigation across the track', () => {
    render(<WegZurAuszeichnungSection />)
    const track = screen.getByTestId('timeline-track')
    const scrollTo = vi.fn()
    Object.defineProperties(track, {
      clientWidth: { configurable: true, value: 400 },
      scrollTo: { configurable: true, value: scrollTo },
      scrollWidth: { configurable: true, value: 1000 },
    })

    fireEvent.keyDown(track, { key: 'End' })

    expect(scrollTo).toHaveBeenCalledWith({ behavior: 'smooth', left: 600 })
    expect(screen.getByTestId('timeline-progress-label').textContent).toContain('04 / 04')
  })
})
