import { Box, IconButton, useTheme } from '@mui/material'
import {
  SubdirectoryArrowLeftOutlined,
  ZoomInOutlined,
} from '@mui/icons-material'
import { useEffect, useCallback } from 'react'
import { widgetStoreActions } from '../../stores/widget-store'
import type { ZoomToggleProps, ZoomState } from './types'
import { styles } from './style'
import { Tooltip } from '../../../components'
import { getEChartZoomConfig } from '../../echart/utils'
import type { EchartOptionsProps } from '../../echart/types'
import { useWidgetSelector } from '../../stores/use-widget-selector'

export const ZOOM_TOGGLE_TOOL_ID = 'zoom-toggle'

/**
 * Widget action to toggle EChart zoom functionality.
 *
 * Registers as a config pipeline tool so that zoom configuration is automatically
 * re-applied when the base config is updated (e.g., by WidgetLoader).
 *
 * Zoom state (enabled, range) is stored in the widget store root, and the tool
 * derives its `enabled` flag from the store. This keeps state accessible across
 * component instances.
 *
 * When zoom is active, displays an inline reset button to disable zoom.
 * Only intended for use in fullscreen ToolbarActions for bar and histogram widgets.
 *
 * @example
 * ```tsx
 * <ZoomToggle
 *   id="my-widget"
 *   defaultZoom={false}
 *   zoomStart={0}
 *   zoomEnd={100}
 * />
 * ```
 */
export function ZoomToggle({
  id,
  defaultZoom = false,
  defaultZoomStart = 0,
  defaultZoomEnd = 100,
  labels,
  Icon,
  ResetIcon,
  IconButtonProps,
}: ZoomToggleProps) {
  const theme = useTheme()

  // Read zoom state from widget store root — single source of truth
  const { zoom, zoomStart, zoomEnd } = useWidgetSelector(id, (w) => ({
    zoom: (w as ZoomState | undefined)?.zoom ?? defaultZoom,
    zoomStart: (w as ZoomState | undefined)?.zoomStart ?? defaultZoomStart,
    zoomEnd: (w as ZoomState | undefined)?.zoomEnd ?? defaultZoomEnd,
  }))

  // Initialize store with default values on mount
  useEffect(() => {
    const current = widgetStoreActions.getWidget<ZoomState>(id)
    if (current?.zoom === undefined) {
      widgetStoreActions.setWidget(id, {
        zoom: defaultZoom,
        zoomStart: defaultZoomStart,
        zoomEnd: defaultZoomEnd,
      })
    }
  }, [id, defaultZoom, defaultZoomStart, defaultZoomEnd])

  // Handle dataZoom event — update store (source of truth)
  const handleDataZoom = useCallback(
    (event: unknown) => {
      const zoomEvent = event as {
        start?: number
        end?: number
        batch?: {
          start?: number
          end?: number
        }[]
      }

      const start = zoomEvent.start ?? zoomEvent.batch?.[0]?.start
      const end = zoomEvent.end ?? zoomEvent.batch?.[0]?.end

      if (start !== undefined && end !== undefined) {
        widgetStoreActions.setWidget(id, {
          zoom: true,
          zoomStart: start,
          zoomEnd: end,
        })
      }
    },
    [id],
  )

  // Register config tool once — fn reads zoom range from the store at execution time.
  useEffect(() => {
    widgetStoreActions.registerTool(id, {
      id: ZOOM_TOGGLE_TOOL_ID,
      type: 'config',
      order: 20,
      enabled: defaultZoom,
      fn: (currentConfig) => {
        const config = currentConfig as Record<string, unknown>
        const option = config.option as EchartOptionsProps | undefined
        const currentOnEvents =
          (config.onEvents as Record<string, unknown> | undefined) ?? {}

        const widget = widgetStoreActions.getWidget<ZoomState>(id)
        const start = widget?.zoomStart ?? 0
        const end = widget?.zoomEnd ?? 100

        const legend = option?.legend as { show?: boolean } | undefined
        const hasLegend = legend?.show !== false && legend !== undefined

        const sliderHeight = parseInt(theme?.spacing?.(4) ?? '32')
        const sliderGap = 8
        const legendBottomOffset = hasLegend ? 28 : 0

        const zoomConfig = getEChartZoomConfig(
          { start, end },
          {
            inside: true,
            xSlider: true,
            ySlider: false,
            bottomOffset: legendBottomOffset,
          },
          theme,
        )

        const grid = option?.grid as { bottom?: number | string } | undefined
        const currentGridBottom =
          typeof grid?.bottom === 'number'
            ? grid.bottom
            : parseInt(grid?.bottom ?? '24')

        const gridBottom = currentGridBottom + sliderHeight + sliderGap

        const onEvents = { ...currentOnEvents, dataZoom: handleDataZoom }

        return {
          ...config,
          option: {
            ...option,
            ...zoomConfig,
            grid: { ...grid, bottom: gridBottom },
          },
          onEvents,
        }
      },
    })
    return () => widgetStoreActions.unregisterTool(id, ZOOM_TOGGLE_TOOL_ID)
  }, [id, theme, handleDataZoom, defaultZoom, defaultZoomStart, defaultZoomEnd])

  // Sync enabled from store — lightweight, no re-registration
  useEffect(() => {
    widgetStoreActions.setToolEnabled(id, ZOOM_TOGGLE_TOOL_ID, zoom)
  }, [id, zoom])

  // Trigger pipeline when zoom range changes — fn reads from store at execution time,
  // but the pipeline only re-runs when registeredTools reference changes.
  // setToolEnabled handles the zoom on/off case, this handles range-only changes.
  useEffect(() => {
    widgetStoreActions.triggerToolPipeline(id)
  }, [id, zoomStart, zoomEnd])

  const handleToggle = () => {
    const newZoom = !zoom
    widgetStoreActions.setWidget(id, {
      zoom: newZoom,
      zoomStart: newZoom ? zoomStart : 0,
      zoomEnd: newZoom ? zoomEnd : 100,
    })
  }

  const handleReset = () => {
    widgetStoreActions.setWidget(id, {
      zoom: true,
      zoomStart: defaultZoomStart,
      zoomEnd: defaultZoomEnd,
    })
  }

  const enableLabel = labels?.enable ?? 'Enable zoom'
  const disableLabel = labels?.disable ?? 'Disable zoom'
  const resetLabel = labels?.reset ?? 'Reset zoom'
  const tooltipLabel = zoom ? disableLabel : enableLabel

  return (
    <Box sx={styles.container}>
      <Tooltip title={tooltipLabel}>
        <IconButton
          size='small'
          aria-label={labels?.ariaLabel ?? tooltipLabel}
          onClick={handleToggle}
          sx={styles.trigger}
          data-active={zoom}
          {...IconButtonProps}
        >
          {Icon ?? <ZoomInOutlined />}
        </IconButton>
      </Tooltip>
      {zoom && (
        <Tooltip title={resetLabel}>
          <IconButton
            size='small'
            aria-label={resetLabel}
            onClick={handleReset}
            {...IconButtonProps}
          >
            {ResetIcon ?? <SubdirectoryArrowLeftOutlined />}
          </IconButton>
        </Tooltip>
      )}
    </Box>
  )
}
