import { describe, expect, test, beforeEach } from 'vitest'
import { act } from '@testing-library/react'
import { useLegend } from './use-legend'
import { useLayerStore } from './providers/layers/store'
import { render } from '../tests/providers'
import type { Layer } from './providers/layers/types'

describe('useLegend', () => {
  beforeEach(() => {
    // Reset store before each test
    useLayerStore.setState({ layers: {} })
  })

  test('returns empty legend when no layers provided', () => {
    const TestComponent = () => {
      const { legend } = useLegend([], (layer: Layer) => ({
        id: layer.props.id,
        name: layer.name,
      }))

      return <div data-testid='count'>{legend.length}</div>
    }

    const { container } = render(<TestComponent />)
    expect(container.querySelector('[data-testid="count"]')?.textContent).toBe(
      '0',
    )
  })

  test('returns legend for layers with legend property', () => {
    const TestComponent = () => {
      const setLayer = useLayerStore((state) => state.setLayer)
      const layers = useLayerStore((state) => state.layers)

      // Only set layers if they don't exist to prevent infinite loop
      if (!layers['layer-1']) {
        setLayer('layer-1', {
          type: null,
          name: 'Layer 1',
          props: { id: 'layer-1', visible: true },
          legend: { switchable: true },
        })
      }
      if (!layers['layer-2']) {
        setLayer('layer-2', {
          type: null,
          name: 'Layer 2',
          props: { id: 'layer-2', visible: true },
          legend: { switchable: false },
        })
      }
      if (!layers['layer-3']) {
        setLayer('layer-3', {
          type: null,
          name: 'Layer 3',
          props: { id: 'layer-3', visible: true },
          // No legend property
        })
      }

      const { legend } = useLegend(
        ['layer-1', 'layer-2', 'layer-3'],
        (layer: Layer) => ({
          id: layer.props.id,
          name: layer.name,
        }),
      )

      return <div data-testid='count'>{legend.length}</div>
    }

    const { container } = render(<TestComponent />)
    // Only layer-1 and layer-2 have legends
    expect(container.querySelector('[data-testid="count"]')?.textContent).toBe(
      '2',
    )
  })

  test('callback transforms layer data correctly', () => {
    const TestComponent = () => {
      const setLayer = useLayerStore((state) => state.setLayer)
      const layers = useLayerStore((state) => state.layers)

      // Only set layer if it doesn't exist to prevent infinite loop
      if (!layers['layer-1']) {
        setLayer('layer-1', {
          type: null,
          name: 'Test Layer',
          props: { id: 'layer-1', visible: true, opacity: 0.8 },
          legend: { switchable: true },
        })
      }

      const { legend } = useLegend(['layer-1'], (layer: Layer) => ({
        id: layer.props.id,
        name: layer.name,
        opacity: layer.props.opacity,
        visible: layer.props.visible,
      }))

      return (
        <div>
          <div data-testid='id'>{legend[0]?.id}</div>
          <div data-testid='name'>{legend[0]?.name}</div>
          <div data-testid='opacity'>{legend[0]?.opacity}</div>
          <div data-testid='visible'>{String(legend[0]?.visible)}</div>
        </div>
      )
    }

    const { container } = render(<TestComponent />)
    expect(container.querySelector('[data-testid="id"]')?.textContent).toBe(
      'layer-1',
    )
    expect(container.querySelector('[data-testid="name"]')?.textContent).toBe(
      'Test Layer',
    )
    expect(
      container.querySelector('[data-testid="opacity"]')?.textContent,
    ).toBe('0.8')
    expect(
      container.querySelector('[data-testid="visible"]')?.textContent,
    ).toBe('true')
  })

  test('onChangeVisibility updates layer visibility and legend', () => {
    const TestComponent = () => {
      const setLayer = useLayerStore((state) => state.setLayer)
      const layers = useLayerStore((state) => state.layers)

      // Only set layer if it doesn't exist to prevent infinite loop
      if (!layers['layer-1']) {
        setLayer('layer-1', {
          type: null,
          name: 'Test Layer',
          props: { id: 'layer-1', visible: true },
          legend: { switchable: true, collapsed: false },
        })
      }

      const { onChangeVisibility } = useLegend(['layer-1'], (layer: Layer) => ({
        id: layer.props.id,
      }))

      const handleClick = () => {
        onChangeVisibility({
          id: 'layer-1',
          visible: false,
          collapsed: true,
        })
      }

      return (
        <div>
          <button onClick={handleClick} data-testid='toggle'>
            Toggle
          </button>
          <div data-testid='visible'>
            {String(layers['layer-1']?.props.visible)}
          </div>
          <div data-testid='collapsed'>
            {String(layers['layer-1']?.legend?.collapsed)}
          </div>
        </div>
      )
    }

    const { container } = render(<TestComponent />)
    const button = container.querySelector<HTMLButtonElement>(
      '[data-testid="toggle"]',
    )!

    // Initial state
    expect(
      container.querySelector('[data-testid="visible"]')?.textContent,
    ).toBe('true')
    expect(
      container.querySelector('[data-testid="collapsed"]')?.textContent,
    ).toBe('false')

    // Click to toggle
    act(() => {
      button.click()
    })

    // After toggle
    expect(
      container.querySelector('[data-testid="visible"]')?.textContent,
    ).toBe('false')
    expect(
      container.querySelector('[data-testid="collapsed"]')?.textContent,
    ).toBe('true')
  })

  test('onChangeOpacity updates layer opacity', () => {
    const TestComponent = () => {
      const setLayer = useLayerStore((state) => state.setLayer)
      const layers = useLayerStore((state) => state.layers)

      // Only set layer if it doesn't exist to prevent infinite loop
      if (!layers['layer-1']) {
        setLayer('layer-1', {
          type: null,
          props: { id: 'layer-1', opacity: 1.0 },
          legend: { opacityControl: true },
        })
      }

      const { onChangeOpacity } = useLegend(['layer-1'], (layer: Layer) => ({
        id: layer.props.id,
      }))

      const handleChange = () => {
        onChangeOpacity({ id: 'layer-1', opacity: 0.5 })
      }

      return (
        <div>
          <button onClick={handleChange} data-testid='change-opacity'>
            Change Opacity
          </button>
          <div data-testid='opacity'>{layers['layer-1']?.props.opacity}</div>
        </div>
      )
    }

    const { container } = render(<TestComponent />)
    const button = container.querySelector<HTMLButtonElement>(
      '[data-testid="change-opacity"]',
    )!

    expect(
      container.querySelector('[data-testid="opacity"]')?.textContent,
    ).toBe('1')

    act(() => {
      button.click()
    })

    expect(
      container.querySelector('[data-testid="opacity"]')?.textContent,
    ).toBe('0.5')
  })

  test('onChangeRowCollapse updates layer collapse state', () => {
    const TestComponent = () => {
      const setLayer = useLayerStore((state) => state.setLayer)
      const layers = useLayerStore((state) => state.layers)

      // Only set layer if it doesn't exist to prevent infinite loop
      if (!layers['layer-1']) {
        setLayer('layer-1', {
          type: null,
          props: { id: 'layer-1' },
          legend: { collapsed: false, collapsible: true },
        })
      }

      const { onChangeRowCollapse } = useLegend(
        ['layer-1'],
        (layer: Layer) => ({
          id: layer.props.id,
        }),
      )

      const handleCollapse = () => {
        onChangeRowCollapse({ id: 'layer-1', collapsed: true })
      }

      return (
        <div>
          <button onClick={handleCollapse} data-testid='collapse'>
            Collapse
          </button>
          <div data-testid='collapsed'>
            {String(layers['layer-1']?.legend?.collapsed)}
          </div>
        </div>
      )
    }

    const { container } = render(<TestComponent />)
    const button = container.querySelector<HTMLButtonElement>(
      '[data-testid="collapse"]',
    )!

    expect(
      container.querySelector('[data-testid="collapsed"]')?.textContent,
    ).toBe('false')

    act(() => {
      button.click()
    })

    expect(
      container.querySelector('[data-testid="collapsed"]')?.textContent,
    ).toBe('true')
  })

  test('layers are sorted and reversed correctly', () => {
    const TestComponent = () => {
      const setLayer = useLayerStore((state) => state.setLayer)
      const layers = useLayerStore((state) => state.layers)

      // Only set layers if they don't exist to prevent infinite loop
      if (!layers['layer-1']) {
        setLayer('layer-1', {
          type: null,
          name: 'Layer 1',
          props: { id: 'layer-1' },
          legend: { switchable: true },
          order: 1,
        })
      }
      if (!layers['layer-2']) {
        setLayer('layer-2', {
          type: null,
          name: 'Layer 2',
          props: { id: 'layer-2' },
          legend: { switchable: true },
          order: 2,
        })
      }
      if (!layers['layer-3']) {
        setLayer('layer-3', {
          type: null,
          name: 'Layer 3',
          props: { id: 'layer-3' },
          legend: { switchable: true },
          order: 3,
        })
      }

      const { legend } = useLegend(
        ['layer-1', 'layer-2', 'layer-3'],
        (layer: Layer) => ({
          id: layer.props.id,
          name: layer.name,
        }),
      )

      return (
        <div>
          <div data-testid='first'>{legend[0]?.id}</div>
          <div data-testid='second'>{legend[1]?.id}</div>
          <div data-testid='third'>{legend[2]?.id}</div>
        </div>
      )
    }

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

    // Should be reversed (highest order first)
    expect(container.querySelector('[data-testid="first"]')?.textContent).toBe(
      'layer-3',
    )
    expect(container.querySelector('[data-testid="second"]')?.textContent).toBe(
      'layer-2',
    )
    expect(container.querySelector('[data-testid="third"]')?.textContent).toBe(
      'layer-1',
    )
  })
})
