import { Box, useTheme } from '@mui/material'
import { useWidgetSelector } from '../stores/use-widget-selector'
import { styles } from './style'
import type { CategoryUIProps, CategoryWidgetState } from './types'
import { CategoryRowSingle } from './components/category-row-single'
import { CategoryRowMulti } from './components/category-row-multi'
import { CategoryRowOther } from './components/category-row-other'
import { CategoryLegend } from './components/category-legend'
import { useState } from 'react'
import { defaultFormatter, defaultLabelFormatter } from '../utils/formatter'
import { useWidgetRef } from '../../hooks'

/**
 * Renders a category widget displaying horizontal bars for categorical data with support for single and multi-series layouts, selection, and overflow grouping.
 */
export function CategoryUI({ id }: CategoryUIProps) {
  const { ref } = useWidgetRef<HTMLDivElement>(id)
  const theme = useTheme()

  // Single consolidated subscription instead of 9 separate ones.
  const {
    _formatter,
    _labelFormatter,
    _series,
    data,
    maxItems,
    labels,
    onRowClick,
    selected,
    max,
  } = useWidgetSelector(id, (w) => {
    const cw = w as CategoryWidgetState | undefined
    return {
      _formatter: cw?.formatter,
      _labelFormatter: cw?.labelFormatter,
      _series: cw?.series,
      data: cw?.data,
      maxItems: cw?.maxItems,
      labels: cw?.labels,
      onRowClick: cw?.onRowClick,
      selected: cw?.selected,
      max: cw?.max,
    }
  })

  const formatter = _formatter ?? defaultFormatter
  const labelFormatter = _labelFormatter ?? defaultLabelFormatter
  const series = _series ?? []

  const [maxHeight] = useState<string | number | undefined>(
    maxItems ? 40 * (series.length || 1) * maxItems : undefined,
  )

  const qualitativeColors = Object.values(theme.palette.qualitative.bold)

  const colors =
    series.length > 0
      ? series.map(
          (s, index: number) =>
            s.color ??
            qualitativeColors[index % qualitativeColors.length] ??
            theme.palette.secondary.main,
        )
      : [theme.palette.secondary.main]

  // Group data items by name to support multi-series display
  // data is CategoryDataItem[][] where data[seriesIndex] contains items for that series
  const groupedData = generateGroupedData({ data })

  if (groupedData.length === 0) {
    return null
  }

  const maxValue =
    max ?? Math.max(...groupedData.flatMap((item) => item.values))

  // Slice data to maxItems and compute hidden count
  const visibleData =
    maxItems !== undefined && maxItems >= 0
      ? groupedData.slice(0, maxItems)
      : groupedData

  const hiddenCount = groupedData.length - visibleData.length
  const isMulti = series.length > 1

  return (
    <Box
      ref={ref}
      sx={{
        ...styles.root,
      }}
    >
      <Box
        sx={styles.list}
        style={{ maxHeight, overflow: hiddenCount === 0 ? 'auto' : 'hidden' }}
      >
        {isMulti
          ? visibleData.map((item) => (
              <CategoryRowMulti
                key={item.name}
                name={item.name}
                values={item.values}
                maxValue={maxValue}
                colors={colors}
                formatter={formatter}
                labelFormatter={labelFormatter}
                onClick={onRowClick}
                selected={selected?.(item.name) ?? true}
              />
            ))
          : visibleData.map((item) => (
              <CategoryRowSingle
                key={item.name}
                name={item.name}
                value={item.values[0] ?? 0}
                selected={selected?.(item.name) ?? true}
                maxValue={maxValue}
                color={colors[0]!}
                formatter={formatter}
                labelFormatter={labelFormatter}
                onClick={onRowClick}
              />
            ))}
        {hiddenCount > 0 && (
          <CategoryRowOther
            hiddenCount={hiddenCount}
            otherLabel={labels?.other}
            otherCountLabel={labels?.otherCount}
          />
        )}
      </Box>
      {series.length > 0 && <CategoryLegend series={series} colors={colors} />}
    </Box>
  )
}

function generateGroupedData({
  data,
}: {
  data: { name: string; value: number }[][] | undefined
}) {
  if (!data || data.length === 0) return []

  const seriesCount = Math.max(data.length, 1)
  const grouped = new Map<string, number[]>()
  const nameOrder: string[] = []

  // Iterate over each series (outer array)
  for (let seriesIndex = 0; seriesIndex < data.length; seriesIndex++) {
    const seriesData = data[seriesIndex]!
    for (const item of seriesData) {
      let values = grouped.get(item.name)
      if (!values) {
        values = new Array<number>(seriesCount).fill(0)
        grouped.set(item.name, values)
        nameOrder.push(item.name)
      }
      values[seriesIndex] = item.value
    }
  }

  return nameOrder.map((name) => ({
    name,
    values: grouped.get(name)!,
  }))
}
