import React, { StrictMode } from 'react'
import { cleanup, render, waitFor } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import type { Metric } from 'web-vitals'

const observerSpies = vi.hoisted(() => ({
  onCLS: vi.fn(),
  onFCP: vi.fn(),
  onINP: vi.fn(),
  onLCP: vi.fn(),
  onTTFB: vi.fn(),
}))

vi.mock('web-vitals', () => observerSpies)

afterEach(() => {
  cleanup()
  vi.clearAllMocks()
  vi.resetModules()
  window.history.replaceState({}, '', '/')
})

describe('@platform-modules/perf-react', () => {
  it('registers every web-vitals observer with a route-tagging reporter seam', async () => {
    window.history.replaceState({}, '', '/reports?tab=vitals#current')
    const { reportWebVitals } = await import('./index')
    const reporter = { report: vi.fn() }

    await reportWebVitals(reporter)

    const callback = observerSpies.onCLS.mock.calls[0]?.[0] as ((metric: Metric) => void) | undefined
    expect(observerSpies.onCLS).toHaveBeenCalledWith(callback)
    expect(observerSpies.onFCP).toHaveBeenCalledWith(expect.any(Function))
    expect(observerSpies.onINP).toHaveBeenCalledWith(expect.any(Function))
    expect(observerSpies.onLCP).toHaveBeenCalledWith(expect.any(Function))
    expect(observerSpies.onTTFB).toHaveBeenCalledWith(expect.any(Function))

    callback?.({
      name: 'CLS',
      value: 0.01,
      rating: 'good',
    } as Metric)

    expect(reporter.report).toHaveBeenCalledWith({
      name: 'CLS',
      value: 0.01,
      rating: 'good',
      route: '/reports?tab=vitals#current',
    })
  })

  it('beacon registers exactly once across multiple mounts', async () => {
    const { WebVitalsBeacon } = await import('./index')
    const reporter = { report: vi.fn() }

    const first = render(
      React.createElement(
        StrictMode,
        null,
        React.createElement(WebVitalsBeacon, { reporter }),
      ),
    )

    expect(first.container.innerHTML).toBe('')

    await waitFor(() => {
      expect(observerSpies.onCLS).toHaveBeenCalledTimes(1)
      expect(observerSpies.onFCP).toHaveBeenCalledTimes(1)
      expect(observerSpies.onINP).toHaveBeenCalledTimes(1)
      expect(observerSpies.onLCP).toHaveBeenCalledTimes(1)
      expect(observerSpies.onTTFB).toHaveBeenCalledTimes(1)
    })

    first.unmount()
    render(React.createElement(WebVitalsBeacon, { reporter }))

    await waitFor(() => {
      expect(observerSpies.onCLS).toHaveBeenCalledTimes(1)
      expect(observerSpies.onFCP).toHaveBeenCalledTimes(1)
      expect(observerSpies.onINP).toHaveBeenCalledTimes(1)
      expect(observerSpies.onLCP).toHaveBeenCalledTimes(1)
      expect(observerSpies.onTTFB).toHaveBeenCalledTimes(1)
    })
  })
})
