import React from 'react'
import { act, render } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import BackgroundPattern from './BackgroundPattern'
import DotCloudIcon from './DotCloudIcon'

const context = {
  arc: vi.fn(),
  beginPath: vi.fn(),
  clearRect: vi.fn(),
  closePath: vi.fn(),
  drawImage: vi.fn(),
  ellipse: vi.fn(),
  fill: vi.fn(),
  getImageData: vi.fn(() => ({ data: new Uint8ClampedArray(140 * 140 * 4) })),
  lineTo: vi.fn(),
  moveTo: vi.fn(),
  quadraticCurveTo: vi.fn(),
  scale: vi.fn(),
  setTransform: vi.fn(),
}

function setReducedMotion(matches) {
  vi.stubGlobal('matchMedia', vi.fn(() => ({
    matches,
    addEventListener: vi.fn(),
    removeEventListener: vi.fn(),
  })))
}

describe('canvas animation lifecycle', () => {
  beforeEach(() => {
    vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue(context)
    Object.defineProperty(document, 'hidden', { configurable: true, value: false })
    vi.stubGlobal('requestAnimationFrame', vi.fn(() => 17))
    vi.stubGlobal('cancelAnimationFrame', vi.fn())
  })

  afterEach(() => {
    vi.restoreAllMocks()
    vi.unstubAllGlobals()
  })

  it('does not schedule background animation with reduced motion', () => {
    setReducedMotion(true)
    render(<BackgroundPattern />)
    expect(requestAnimationFrame).not.toHaveBeenCalled()
  })

  it('cancels a scheduled background frame on unmount', () => {
    setReducedMotion(false)
    const { unmount } = render(<BackgroundPattern />)
    expect(requestAnimationFrame).toHaveBeenCalled()

    unmount()
    expect(cancelAnimationFrame).toHaveBeenCalledWith(17)
  })

  it('does not schedule dot animation with reduced motion', async () => {
    setReducedMotion(true)
    render(<DotCloudIcon shape="shield" />)
    await act(async () => Promise.resolve())
    expect(requestAnimationFrame).not.toHaveBeenCalled()
  })
})
