import { afterEach, describe, it, expect } from 'vitest'
import { act, fireEvent, render, screen } from '@testing-library/react'
import { LegendProvider } from '../../provider'
import { LegendVisibleLayers } from './legend-visible-layers'
import {
  clearAllLegendStores,
  getLegendStore,
  type LegendLayerInput,
  type LegendVariable,
} from '../../stores'

const cat: LegendVariable = {
  type: 'category',
  items: [{ label: 'A', color: '#123456' }],
}

const layers: LegendLayerInput[] = [
  { id: 'a', name: 'Suitability', groupId: 'g1', variables: [cat] },
  { id: 'b', name: 'Population', groupId: 'g2', variables: [cat] },
  { id: 'c', name: 'Facilities', variables: [cat] }, // ungrouped → last
]
const groups = [
  { id: 'g1', label: 'Site selection' },
  { id: 'g2', label: 'Demographics' },
]

afterEach(() => clearAllLegendStores())

function renderSummary(id: string, layerInputs = layers) {
  return render(
    <LegendProvider id={id} layers={layerInputs} groups={groups}>
      <LegendVisibleLayers />
    </LegendProvider>,
  )
}

describe('<LegendVisibleLayers>', () => {
  it('lists only visible layers grouped under their captions, ungrouped last', () => {
    renderSummary('vl1', [
      ...layers.slice(0, 2),
      { ...layers[2]!, visible: false } as LegendLayerInput,
    ])
    fireEvent.click(screen.getByLabelText('Enabled layers'))
    // Count excludes the hidden ungrouped layer.
    expect(screen.getByText('Enabled layers (2)')).toBeTruthy()
    expect(screen.getByText('Site selection')).toBeTruthy()
    expect(screen.getByText('Suitability')).toBeTruthy()
    expect(screen.getByText('Population')).toBeTruthy()
    // Hidden layer (and its would-be section) not listed.
    expect(screen.queryByText('Facilities')).toBeNull()
  })

  it('clicking an entry hides the layer and removes it without closing the menu', () => {
    renderSummary('vl2')
    fireEvent.click(screen.getByLabelText('Enabled layers'))
    expect(screen.getByText('Enabled layers (3)')).toBeTruthy()

    // The whole item is the hide action (keyboard-reachable menu item).
    fireEvent.click(screen.getByRole('menuitem', { name: 'Suitability' }))
    expect(getLegendStore('vl2').getState().layers.a!.visible).toBe(false)
    // Menu stayed open, entry gone, count updated live.
    expect(screen.getByText('Enabled layers (2)')).toBeTruthy()
    expect(screen.queryByText('Suitability')).toBeNull()
  })

  it('hiding the last visible layer closes the menu and disables the trigger', () => {
    renderSummary('vl3', [layers[0]!])
    const trigger = screen.getByLabelText<HTMLButtonElement>('Enabled layers')
    fireEvent.click(trigger)
    fireEvent.click(screen.getByRole('menuitem', { name: 'Suitability' }))
    // Nothing left to list → the menu closed itself (role queries skip the
    // aria-hidden exit transition)…
    expect(screen.queryByRole('menu')).toBeNull()
    // …and the trigger is disabled until a layer is shown again.
    expect(trigger.disabled).toBe(true)
  })

  it('closes when the last visible layer is hidden from elsewhere', () => {
    renderSummary('vl4', [layers[0]!])
    fireEvent.click(screen.getByLabelText('Enabled layers'))
    expect(screen.getByRole('menu')).toBeTruthy()
    // External change (e.g. a row eye) while the menu is open.
    act(() => getLegendStore('vl4').getState().setVisibility('a', false))
    expect(screen.queryByRole('menu')).toBeNull()
  })
})
