import { describe, it, expect, vi, beforeEach } from 'vitest'
import { useEventManager, EVENT_TYPES } from './use-event-manager'
import { render } from '../tests/providers'
import { useLayerStore } from './providers/layers/store'
import { MAP_ID } from '../tests/config'

// Mock mjolnir.js
vi.mock('mjolnir.js', () => {
  const mockDestroy = vi.fn()
  const MockEventManager = vi.fn(() => ({
    destroy: mockDestroy,
  }))

  return {
    EventManager: MockEventManager,
    Pan: vi.fn(),
    InputDirection: {
      Vertical: 1,
    },
    Pinch: vi.fn(),
    Tap: vi.fn(),
  }
})

describe('useEventManager', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    useLayerStore.setState({ layers: {} })
  })

  it('should export EVENT_TYPES constant with all event types', () => {
    expect(EVENT_TYPES).toEqual([
      'click',
      'keyup',
      'panstart',
      'panmove',
      'panend',
      'pointermove',
    ])
    expect(EVENT_TYPES.length).toBe(6)
  })

  it('should have correct number of event types', () => {
    expect(EVENT_TYPES.length).toBeGreaterThan(0)
    EVENT_TYPES.forEach((eventType) => {
      expect(typeof eventType).toBe('string')
    })
  })

  it('should set layer with null eventManager for non-Google Maps basemaps', () => {
    const TestComponent = () => {
      useEventManager({ mapId: MAP_ID, layerId: 'test-layer-1' })
      const layers = useLayerStore((state) => state.layers)
      const layer = layers['test-layer-1']
      return (
        <div data-testid='event-manager'>
          {(layer?.props as { eventManager?: unknown })?.eventManager === null
            ? 'null'
            : 'not-null'}
        </div>
      )
    }

    const { container } = render(<TestComponent />)

    const element = container.querySelector('[data-testid="event-manager"]')
    expect(element?.textContent).toBe('null')
  })

  it('should update layer store with eventManager prop', () => {
    const TestComponent = () => {
      useEventManager({ mapId: MAP_ID, layerId: 'test-layer-2' })
      const layers = useLayerStore((state) => state.layers)
      return (
        <div data-testid='has-layer'>
          {'test-layer-2' in layers ? 'true' : 'false'}
        </div>
      )
    }

    const { container } = render(<TestComponent />)

    const element = container.querySelector('[data-testid="has-layer"]')
    expect(element?.textContent).toBe('true')
  })

  it('should handle multiple layers with different IDs', () => {
    const TestComponent = () => {
      useEventManager({ mapId: MAP_ID, layerId: 'layer-3' })
      useEventManager({ mapId: MAP_ID, layerId: 'layer-4' })
      const layers = useLayerStore((state) => state.layers)
      return (
        <div>
          <div data-testid='layer-1'>
            {'layer-3' in layers ? 'true' : 'false'}
          </div>
          <div data-testid='layer-2'>
            {'layer-4' in layers ? 'true' : 'false'}
          </div>
        </div>
      )
    }

    const { container } = render(<TestComponent />)

    const layer1 = container.querySelector('[data-testid="layer-1"]')
    const layer2 = container.querySelector('[data-testid="layer-2"]')
    expect(layer1?.textContent).toBe('true')
    expect(layer2?.textContent).toBe('true')
  })

  it('should cleanup eventManager on unmount', () => {
    const TestComponent = () => {
      useEventManager({ mapId: MAP_ID, layerId: 'test-layer-5' })
      return <div>Test</div>
    }

    const { unmount } = render(<TestComponent />)

    unmount()

    // The cleanup function should be called (though we can't directly test the destroy call
    // without Google Maps setup, we can verify the component unmounts without errors)
    expect(true).toBe(true)
  })

  it('should handle layer updates', () => {
    const TestComponent = () => {
      useEventManager({ mapId: MAP_ID, layerId: 'test-layer-6' })
      const layers = useLayerStore((state) => state.layers)
      const layer = layers['test-layer-6']
      return (
        <div data-testid='layer-props'>
          {layer?.props ? 'has-props' : 'no-props'}
        </div>
      )
    }

    const { container } = render(<TestComponent />)

    const element = container.querySelector('[data-testid="layer-props"]')
    expect(element?.textContent).toBe('has-props')
  })

  it('should set eventManager prop on layer', () => {
    const TestComponent = () => {
      useEventManager({ mapId: MAP_ID, layerId: 'test-layer-7' })
      const layers = useLayerStore((state) => state.layers)
      const layer = layers['test-layer-7']
      const hasEventManager = 'eventManager' in (layer?.props ?? {})
      return (
        <div data-testid='has-event-manager'>
          {hasEventManager ? 'true' : 'false'}
        </div>
      )
    }

    const { container } = render(<TestComponent />)

    const element = container.querySelector('[data-testid="has-event-manager"]')
    expect(element?.textContent).toBe('true')
  })

  it('should store layer in layer store', () => {
    const TestComponent = () => {
      useEventManager({ mapId: MAP_ID, layerId: 'test-layer-8' })
      return <div>Test</div>
    }

    render(<TestComponent />)

    const layers = useLayerStore.getState().layers
    expect('test-layer-8' in layers).toBe(true)
  })

  it('should re-run effect when mapId changes', () => {
    const TestComponent = ({ mapId }: { mapId: string }) => {
      useEventManager({ mapId, layerId: 'test-layer-9' })
      return <div>Test</div>
    }

    const { rerender } = render(<TestComponent mapId={MAP_ID} />)

    const firstLayer = useLayerStore.getState().layers['test-layer-9']
    expect(firstLayer).toBeDefined()

    // Re-render with same mapId to test effect re-run
    rerender(<TestComponent mapId={MAP_ID} />)

    const secondLayer = useLayerStore.getState().layers['test-layer-9']
    expect(secondLayer).toBeDefined()
  })

  it('should re-run effect when layerId changes', () => {
    const TestComponent = ({ layerId }: { layerId: string }) => {
      useEventManager({ mapId: MAP_ID, layerId })
      return <div>Test</div>
    }

    const { rerender } = render(<TestComponent layerId='layer-10' />)

    expect(useLayerStore.getState().layers['layer-10']).toBeDefined()

    rerender(<TestComponent layerId='layer-11' />)

    expect(useLayerStore.getState().layers['layer-11']).toBeDefined()
  })
})
