import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { render, screen, fireEvent, waitFor, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import Scanner from '@/components/Scanner'

// Helper to reduce render() duplication
const renderScanner = (props = {}) => {
  const defaultProps = {
    onScanSuccess: vi.fn(),
    onOCRMatch: vi.fn(),
    paused: false,
    ...props,
  }
  return render(<Scanner {...defaultProps} />)
}

describe('Scanner Component', () => {
  afterEach(() => {
    vi.clearAllMocks()
  })
  // ============================================================================
  // UNIT TESTS: Rendering (Core Structure)
  // ============================================================================

  describe('Rendering', () => {
    it('should render scanner with viewport and controls', () => {
      const { container } = renderScanner()
      const viewport = container.querySelector('.aspect-square')
      const controls = container.querySelector('.bg-surface\\/50')
      expect(viewport).toBeInTheDocument()
      expect(controls).toBeInTheDocument()
    })
  })

  // ============================================================================
  // UNIT TESTS: Callback Props
  // ============================================================================

  describe('Callback Props', () => {
    it('should accept onScanSuccess and onOCRMatch callbacks', () => {
      const mockSuccess = vi.fn()
      const mockOCR = vi.fn()
      renderScanner({ onScanSuccess: mockSuccess, onOCRMatch: mockOCR })
      expect(mockSuccess).toBeDefined()
      expect(mockOCR).toBeDefined()
    })

    it('should render with minimal props (onScanSuccess only)', () => {
      const mockSuccess = vi.fn()
      const { container } = render(
        <Scanner onScanSuccess={mockSuccess} />
      )
      expect(container).toBeInTheDocument()
    })

    it('should accept paused prop and pass through', () => {
      const { container } = renderScanner({ paused: true })
      expect(container).toBeInTheDocument()
    })
  })

  // ============================================================================
  // UNIT TESTS: Zoom Controls & Accessibility
  // ============================================================================

  describe('Zoom Control & Buttons', () => {
    it('should render buttons with accessibility attributes', () => {
      const { container } = renderScanner()
      const buttons = container.querySelectorAll('button')
      expect(buttons.length).toBeGreaterThanOrEqual(0)
      buttons.forEach(btn => {
        // Button should have proper styling
        expect(btn.className).toBeTruthy()
      })
    })

    it('should have focus-ring styling on interactive elements', () => {
      const { container } = renderScanner()
      const buttons = container.querySelectorAll('button')
      if (buttons.length > 0) {
        const firstButton = buttons[0]
        expect(firstButton.className).toMatch(/focus.*ring|focus-visible/)
      }
    })
  })

  // ============================================================================
  // UNIT TESTS: Error Handling
  // ============================================================================

  describe('Error Handling', () => {
    it('should render without throwing on mount with valid props', () => {
      expect(() => {
        renderScanner()
      }).not.toThrow()
    })

    it('should handle unmount without errors', () => {
      const { unmount } = renderScanner()
      expect(() => unmount()).not.toThrow()
    })
  })

  // ============================================================================
  // INTEGRATION TESTS: Scan Workflow
  // ============================================================================

  describe('Scan Workflow (Integration)', () => {
    it('should render scanner with callbacks available', () => {
      const mockSuccess = vi.fn()
      const mockOCR = vi.fn()
      const { container } = renderScanner({ onScanSuccess: mockSuccess, onOCRMatch: mockOCR })

      expect(mockSuccess).toBeDefined()
      expect(mockOCR).toBeDefined()
      expect(container.querySelector('.aspect-square')).toBeInTheDocument()
    })

    it('should clean up on unmount', () => {
      const { unmount, container } = renderScanner()
      expect(container).toBeInTheDocument()
      expect(() => unmount()).not.toThrow()
    })
  })

  // ============================================================================
  // UNIT TESTS: Pause State
  // ============================================================================

  describe('Pause State', () => {
    it('should handle paused prop changes without errors', () => {
      const mockSuccess = vi.fn()
      const mockOCR = vi.fn()
      const { rerender, container } = render(
        <Scanner
          onScanSuccess={mockSuccess}
          onOCRMatch={mockOCR}
          paused={false}
        />
      )

      expect(container).toBeInTheDocument()

      rerender(
        <Scanner
          onScanSuccess={mockSuccess}
          onOCRMatch={mockOCR}
          paused={true}
        />
      )

      expect(container).toBeInTheDocument()
    })
  })

  // ============================================================================
  // LAYOUT & ACCESSIBILITY TESTS
  // ============================================================================

  describe('Layout & Accessibility', () => {
    it('should have responsive Tailwind layout structure', () => {
      const { container } = renderScanner()
      const mainDiv = container.querySelector('.w-full.max-w-md')
      expect(mainDiv).toBeInTheDocument()
      expect(mainDiv?.className).toMatch(/flex/)
    })

    it('should contain text elements for readability', () => {
      const { container } = renderScanner()
      const textElements = container.querySelectorAll('p, span, button')
      expect(textElements.length).toBeGreaterThan(0)
    })

    it('should use Lucide icons (SVG elements)', () => {
      const { container } = renderScanner()
      const svgs = container.querySelectorAll('svg')
      expect(svgs.length).toBeGreaterThanOrEqual(0)
    })
  })

  // ============================================================================
  // COMPONENT PROP VARIATIONS & STABILITY
  // ============================================================================

  describe('Component Prop Variations & Stability', () => {
    it('should render with all props (onScanSuccess, onOCRMatch, paused)', () => {
      const { container } = renderScanner({ paused: false })
      expect(container).toBeInTheDocument()
    })

    it('should render with minimal props (onScanSuccess only)', () => {
      const { container } = render(
        <Scanner onScanSuccess={vi.fn()} />
      )
      expect(container).toBeInTheDocument()
    })

    it('should handle multiple rapid re-renders without errors', () => {
      const mockScan = vi.fn()
      const mockOCR = vi.fn()
      const { rerender } = renderScanner({ onScanSuccess: mockScan, onOCRMatch: mockOCR })

      for (let i = 0; i < 3; i++) {
        expect(() => {
          rerender(
            <Scanner
              onScanSuccess={mockScan}
              onOCRMatch={mockOCR}
            />
          )
        }).not.toThrow()
      }
    })

    it('should handle callback function changes between renders', () => {
      const mockScan1 = vi.fn()
      const mockScan2 = vi.fn()
      const { rerender } = render(
        <Scanner
          onScanSuccess={mockScan1}
          onOCRMatch={vi.fn()}
        />
      )

      rerender(
        <Scanner
          onScanSuccess={mockScan2}
          onOCRMatch={vi.fn()}
        />
      )

      expect(mockScan1).toBeDefined()
      expect(mockScan2).toBeDefined()
    })
  })

  // ============================================================================
  // INTEGRATION: UI Interaction States
  // ============================================================================

  describe('UI Interaction States', () => {
    it('should render viewport and controls in proper visual hierarchy', () => {
      const { container } = renderScanner()
      const viewport = container.querySelector('.aspect-square')
      const controls = container.querySelector('.bg-surface\\/50')
      expect(viewport).toBeInTheDocument()
      expect(controls).toBeInTheDocument()
    })

    it('should have consistent spacing with gap utilities', () => {
      const { container } = renderScanner()
      const mainContainer = container.querySelector('.flex.flex-col')
      expect(mainContainer?.className).toMatch(/gap-/)
    })
  })

  // ============================================================================
  // COMPONENT STABILITY TESTS
  // ============================================================================

  describe('Component Stability', () => {
    it('should mount and unmount without errors', () => {
      expect(() => renderScanner()).not.toThrow()
      const { unmount } = renderScanner()
      expect(() => unmount()).not.toThrow()
    })

    it('should handle rapid paused prop changes', () => {
      const { rerender } = renderScanner({ paused: false })

      for (let i = 0; i < 5; i++) {
        expect(() => {
          rerender(
            <Scanner
              onScanSuccess={vi.fn()}
              onOCRMatch={vi.fn()}
              paused={i % 2 === 0}
            />
          )
        }).not.toThrow()
      }
    })

    it('should render with only required prop (onScanSuccess)', () => {
      expect(() => {
        render(<Scanner onScanSuccess={vi.fn()} />)
      }).not.toThrow()
    })
  })

  // ============================================================================
  // COMPONENT STRUCTURE TESTS
  // ============================================================================

  describe('Component Structure', () => {
    it('should maintain DOM structure on initial render and after prop updates', () => {
      const { rerender, container } = renderScanner({ paused: false })

      // Verify initial structure
      expect(container.querySelector('.w-full.max-w-md')).toBeInTheDocument()
      expect(container.querySelector('.aspect-square')).toBeInTheDocument()
      expect(container.querySelector('.bg-surface\\/50')).toBeInTheDocument()

      // Update props
      rerender(
        <Scanner
          onScanSuccess={vi.fn()}
          onOCRMatch={vi.fn()}
          paused={true}
        />
      )

      // Structure preserved
      expect(container.querySelector('.aspect-square')).toBeInTheDocument()
    })
  })
})
