import { useCallback, useMemo, type ComponentType } from 'react'
import { IconButton, useTheme, type SvgIconProps } from '@mui/material'
import { ZoomIn as ZoomInIcon } from '@mui/icons-material'
import { Tooltip } from '../../../components'
import {
  getEchartInstance,
  useSingleTransform,
  useWidgetId,
} from '../../stores'
import { createAddZoom, type ZoomAxis } from './transforms'
import { DEFAULT_ZOOM_TOGGLE_LABELS, type ZoomToggleLabels } from './labels'
import { styles } from './style'

const ZOOM_DESCRIPTOR = {
  id: 'zoom-toggle',
  type: 'config' as const,
  order: 20,
}

export interface ZoomToggleProps {
  initialEnabled?: boolean
  labels?: Partial<ZoomToggleLabels>
  icon?: ComponentType<SvgIconProps>
  iconProps?: SvgIconProps
  /**
   * Which axes the zoom controls. Default `['x']` — matches bar /
   * histogram / timeseries (horizontal pan on the category axis). Pass
   * `['x', 'y']` for 2D zoom on a scatterplot-style chart (mouse-wheel
   * scales both axes; horizontal slider at bottom + vertical slider on
   * the right).
   */
  axes?: readonly ZoomAxis[]
}

/**
 * Toggle a `dataZoom` slider + wheel-zoom on the chart. The transform is
 * theme-bound so the slider gets v1's CARTO chrome (blue-tinted filler,
 * secondary-color preview, white pill handles).
 *
 * `dataZoom` is intentionally NOT in `replaceMergeKeys` — ECharts merges
 * subsequent `setOption` calls so the user's dragged range survives
 * unrelated re-renders (data updates, formatter swaps, RelativeData toggles).
 *
 * On disable the transform is unregistered, but ECharts' merge semantics
 * would otherwise *keep* the live `dataZoom` component visible. To remove
 * the slider immediately we issue a one-shot
 * `setOption({}, { replaceMerge: ['dataZoom'] })` against the live chart
 * instance via {@link getEchartInstance} — this bypasses the pipeline so
 * unrelated transforms aren't disturbed.
 */
export function ZoomToggle({
  initialEnabled = false,
  labels,
  icon: Icon = ZoomInIcon,
  iconProps,
  axes,
}: ZoomToggleProps) {
  const id = useWidgetId()
  const theme = useTheme()
  const _labels = { ...DEFAULT_ZOOM_TOGGLE_LABELS, ...labels }
  // Reduce `axes` to two structural booleans before memoizing so the memo
  // depends on stable primitive values, not an array reference (callers
  // typically pass an inline `axes={['x', 'y']}` literal that changes
  // identity each render). Default — no `axes` prop — is x-axis only,
  // matching `createAddZoom`'s default.
  const includeX = axes ? axes.includes('x') : true
  const includeY = axes ? axes.includes('y') : false
  const transform = useMemo(() => {
    const resolved: ZoomAxis[] = []
    if (includeX) resolved.push('x')
    if (includeY) resolved.push('y')
    return createAddZoom(theme, { axes: resolved })
  }, [theme, includeX, includeY])
  const { enabled, toggle } = useSingleTransform(
    id,
    ZOOM_DESCRIPTOR,
    transform,
    { initialEnabled },
  )

  const handleToggle = useCallback(() => {
    if (enabled) {
      // About to disable — clear the dataZoom component on the live
      // instance so the slider disappears immediately.
      getEchartInstance(id)?.setOption({}, { replaceMerge: ['dataZoom'] })
    }
    toggle()
  }, [enabled, toggle, id])

  const tooltip = enabled ? _labels.on : _labels.off

  return (
    <Tooltip title={tooltip}>
      <IconButton
        size='small'
        aria-label={tooltip}
        aria-pressed={enabled}
        onClick={handleToggle}
        className={enabled ? 'active' : undefined}
        sx={{ ...styles.toggle, ...(enabled && styles.toggleActive) }}
      >
        <Icon fontSize='small' {...iconProps} />
      </IconButton>
    </Tooltip>
  )
}
