import type { MouseEvent } from 'react'
import { CircularProgress, MenuItem } from '@mui/material'
import {
  getLegendStore,
  selectAllGroupsCollapsed,
  selectGroupVisibility,
  selectHasGroups,
  selectLayersByGroup,
  selectOrderedGroups,
  useLegendId,
  useLegendStore,
} from '../../stores'
import { useLegendConfig } from '../../provider'
import { useLegendGroupId, useLegendMenu } from '../contexts'
import { runAsyncMenuAction } from '../run-async-menu-action'

/**
 * Show only this group (hide all other layers).
 *
 * @experimental This API is new and may change in a future release.
 */
export function LegendShowOnlyGroup() {
  const id = useLegendId()
  const groupId = useLegendGroupId()
  const { labels } = useLegendConfig()

  if (groupId === null) return null

  const showOnly = () => {
    const state = getLegendStore(id).getState()
    for (const group of selectOrderedGroups(state)) {
      state.setGroupVisibility(group.id, group.id === groupId)
    }
    // Exclusive: the ungrouped layers hide too.
    for (const layer of selectLayersByGroup(state, undefined)) {
      state.setVisibility(layer.id, false)
    }
  }

  return <MenuItem onClick={showOnly}>{labels.showOnlyGroup}</MenuItem>
}

/**
 * Show every layer (panel-level `Legend.PanelMenu` only).
 *
 * @experimental This API is new and may change in a future release.
 */
export function LegendShowAllGroups() {
  const id = useLegendId()
  const hasGroups = useLegendStore(id, selectHasGroups)
  const { labels } = useLegendConfig()

  if (!hasGroups) return null

  const showAll = () => {
    const state = getLegendStore(id).getState()
    for (const group of selectOrderedGroups(state)) {
      state.setGroupVisibility(group.id, true)
    }
    for (const layer of selectLayersByGroup(state, undefined)) {
      state.setVisibility(layer.id, true)
    }
  }

  return <MenuItem onClick={showAll}>{labels.showAllGroups}</MenuItem>
}

/**
 * Collapse / expand all groups (panel-level `Legend.PanelMenu` only).
 *
 * @experimental This API is new and may change in a future release.
 */
export function LegendCollapseAllGroups() {
  const id = useLegendId()
  const hasGroups = useLegendStore(id, selectHasGroups)
  const allCollapsed = useLegendStore(id, selectAllGroupsCollapsed)
  const { labels } = useLegendConfig()

  if (!hasGroups) return null

  const toggleAll = () => {
    const state = getLegendStore(id).getState()
    const collapsed = selectAllGroupsCollapsed(state)
    for (const group of selectOrderedGroups(state)) {
      state.setGroupCollapsed(group.id, !collapsed)
    }
  }

  return (
    <MenuItem onClick={toggleAll}>
      {allCollapsed ? labels.expandAllGroups : labels.collapseAllGroups}
    </MenuItem>
  )
}

export interface LegendZoomToGroupProps {
  /** Fit viewport to the group; may return a Promise for async menu feedback. */
  onZoomTo: (groupId: string) => void | Promise<void>
}

/**
 * Zoom-to-group menu item for `Legend.GroupMenu`. Self-hides when all members are hidden.
 *
 * @experimental This API is new and may change in a future release.
 */
export function LegendZoomToGroup({ onZoomTo }: LegendZoomToGroupProps) {
  const id = useLegendId()
  const groupId = useLegendGroupId()
  const menu = useLegendMenu()
  const hidden = useLegendStore(
    id,
    (s) => groupId !== null && selectGroupVisibility(s, groupId) === 'hidden',
  )
  const { labels } = useLegendConfig()

  if (groupId === null || hidden) return null

  const busy = menu?.busy ?? false

  const handleClick = (e: MouseEvent) => {
    e.stopPropagation()
    if (!menu) return
    void runAsyncMenuAction(menu, () => onZoomTo(groupId))
  }

  return (
    <MenuItem disabled={busy} onClick={handleClick}>
      {busy && <CircularProgress size={16} sx={{ mr: 1 }} />}
      {busy ? labels.loading : labels.zoomToGroup}
    </MenuItem>
  )
}
