import { IconButton } from '@mui/material'
import { useCallback, useEffect, useMemo } from 'react'
import { widgetStoreActions } from '../../stores/widget-store'
import type { StackToggleProps, StackToggleState } from './types'
import { actionButtonStyles } from '../shared/styles'
import { Tooltip } from '../../../components'
import { GroupedBarChartIcon } from './grouped-bar-chart-icon'
import { getEChartStackConfig } from '../../echart/utils'
import { DEFAULT_STACK_GROUP } from '../../echart/const'
import type { EchartWidgetState } from '../../echart/types'
import type { EchartOptionsProps } from '../../echart/types'
import { useWidgetSelector } from '../../stores/use-widget-selector'
export const STACK_TOGGLE_TOOL_ID = 'stack-toggle'
/**
* Widget action to toggle stacking behavior in ECharts bar and histogram widgets.
*
* Registers as a config pipeline tool so that stack configuration is automatically
* re-applied when the base config is updated (e.g., by WidgetLoader).
*
* @example
* ```tsx
*
* ```
*/
export function StackToggle({
id,
defaultIsStacked = false,
labels,
Icon,
IconButtonProps,
}: StackToggleProps) {
const { storeIsStacked, option } = useWidgetSelector(id, (w) => ({
storeIsStacked: (w as StackToggleState | undefined)?.isStacked,
option: (w as EchartWidgetState | undefined)?.option,
}))
const { hasMultiSeries, hasStackInSeries } = useMemo(() => {
if (!option) return { hasMultiSeries: false, hasStackInSeries: false }
const series = Array.isArray(option.series)
? option.series
: [option.series]
return {
hasMultiSeries: series.length > 1,
hasStackInSeries: series.some((s) => (s as { stack?: string })?.stack),
}
}, [option])
// If series already has stack defined, default to stacked=true
const effectiveDefaultIsStacked = hasStackInSeries || defaultIsStacked
const isStacked = storeIsStacked ?? effectiveDefaultIsStacked
// Register config tool once — fn has no closure deps
useEffect(() => {
widgetStoreActions.registerTool(id, {
id: STACK_TOGGLE_TOOL_ID,
type: 'config',
order: 10,
enabled: false,
fn: (currentConfig: unknown) => {
const config = currentConfig as Record
const option = config.option as EchartOptionsProps | undefined
if (!option) return currentConfig
const series = Array.isArray(option.series)
? option.series
: [option.series]
const updatedSeries = series.map((s) => {
const existingStack = (s as { stack?: string })?.stack
const stackGroup =
typeof existingStack === 'string'
? existingStack
: DEFAULT_STACK_GROUP
return { ...s, ...getEChartStackConfig(stackGroup) }
})
return { ...config, option: { ...option, series: updatedSeries } }
},
})
return () => widgetStoreActions.unregisterTool(id, STACK_TOGGLE_TOOL_ID)
}, [id])
// Sync enabled from store — lightweight, no re-registration
useEffect(() => {
widgetStoreActions.setToolEnabled(
id,
STACK_TOGGLE_TOOL_ID,
isStacked && hasMultiSeries,
)
}, [id, isStacked, hasMultiSeries])
// Initialize store with default value only if not already configured
useEffect(() => {
if (storeIsStacked !== undefined) return
widgetStoreActions.setWidget(id, { isStacked: effectiveDefaultIsStacked })
}, [effectiveDefaultIsStacked, id, storeIsStacked])
const handleToggle = useCallback(() => {
widgetStoreActions.setWidget(id, { isStacked: !isStacked })
}, [isStacked, id])
const tooltipLabel = isStacked
? (labels?.unstacked ?? 'Disable stacking')
: (labels?.stacked ?? 'Enable stacking')
// Early return if there's only one series - stacking doesn't apply
if (!hasMultiSeries) {
return null
}
return (
{Icon ?? }
)
}