import { useState } from 'react'
import styles from './BarChart.module.css'
import { formatAxisLabel, CHART_COLORS } from '../_chart-utils'

interface BarSeries {
  label: string
  data: { x: string; y: number }[]
  color?: string
}

interface BarChartProps {
  series: BarSeries[]
  stacked?: boolean
  height?: number
  width?: number
  xLabel?: string
  yLabel?: string
  className?: string
}

const PADDING = { top: 12, right: 16, bottom: 40, left: 48 }
const Y_TICK_COUNT = 4
const BAR_GAP = 0.2  // fraction of bar group width reserved for gaps

export function BarChart({
  series,
  stacked = false,
  height = 200,
  width = 400,
  xLabel,
  yLabel,
  className,
}: BarChartProps) {
  const [tooltip, setTooltip] = useState<{
    x: number
    y: number
    label: string
    values: { series: string; value: number; color: string }[]
  } | null>(null)

  if (series.length === 0 || series[0].data.length === 0) {
    return <div className={`${styles.empty} ${className ?? ''}`}>No data</div>
  }

  // Collect all x categories (union across all series)
  const categories = Array.from(new Set(series.flatMap((s) => s.data.map((d) => d.x))))
  const numCats = categories.length

  const plotW = width - PADDING.left - PADDING.right
  const plotH = height - PADDING.top - PADDING.bottom

  // Compute max Y
  let maxY = 0
  if (stacked) {
    for (const cat of categories) {
      const sum = series.reduce((acc, s) => {
        const pt = s.data.find((d) => d.x === cat)
        return acc + (pt?.y ?? 0)
      }, 0)
      maxY = Math.max(maxY, sum)
    }
  } else {
    maxY = Math.max(...series.flatMap((s) => s.data.map((d) => d.y)))
  }
  maxY = maxY || 1

  const yTicks = Array.from({ length: Y_TICK_COUNT + 1 }, (_, i) =>
    Math.round((maxY / Y_TICK_COUNT) * i),
  )
  const toY = (val: number) => PADDING.top + plotH - (val / maxY) * plotH
  const bottomY = PADDING.top + plotH

  const catWidth = plotW / numCats
  const groupGap = catWidth * BAR_GAP
  const groupW = catWidth - groupGap

  function handleMouseEnter(
    catLabel: string,
    mx: number,
    my: number,
    values: { series: string; value: number; color: string }[],
  ) {
    setTooltip({ x: mx, y: my, label: catLabel, values })
  }

  function showBarTooltip(e: React.MouseEvent<SVGRectElement>, cat: string) {
    const rect = e.currentTarget.closest('svg')!.getBoundingClientRect()
    handleMouseEnter(
      cat,
      e.clientX - rect.left,
      e.clientY - rect.top,
      series.map((ss, ssi) => ({
        series: ss.label,
        value: ss.data.find((d) => d.x === cat)?.y ?? 0,
        color: ss.color ?? CHART_COLORS[ssi % CHART_COLORS.length],
      })),
    )
  }

  return (
    <div className={`${styles.wrapper} ${className ?? ''}`}>
      {yLabel && <div className={styles.yLabel}>{yLabel}</div>}
      <svg
        width={width}
        height={height}
        viewBox={`0 0 ${width} ${height}`}
        className={styles.svg}
        onMouseLeave={() => setTooltip(null)}
        aria-label="Bar chart"
        role="img"
      >
        {/* Grid lines */}
        {yTicks.map((val) => {
          const y = toY(val)
          return (
            <g key={val}>
              <line
                x1={PADDING.left}
                y1={y}
                x2={width - PADDING.right}
                y2={y}
                className={styles.gridLine}
              />
              <text x={PADDING.left - 6} y={y + 4} className={styles.axisLabel} textAnchor="end">
                {formatAxisLabel(val)}
              </text>
            </g>
          )
        })}

        {/* Bars */}
        {categories.map((cat, ci) => {
          const groupX = PADDING.left + ci * catWidth + groupGap / 2

          if (stacked) {
            let stackY = bottomY
            return (
              <g key={cat}>
                {series.map((s, si) => {
                  const pt = s.data.find((d) => d.x === cat)
                  const val = pt?.y ?? 0
                  const barH = (val / maxY) * plotH
                  const color = s.color ?? CHART_COLORS[si % CHART_COLORS.length]
                  const y = stackY - barH
                  stackY -= barH
                  return (
                    <rect
                      key={si}
                      x={groupX}
                      y={y}
                      width={groupW}
                      height={barH}
                      fill={color}
                      className={styles.bar}
                      onMouseEnter={(e) => showBarTooltip(e, cat)}
                    />
                  )
                })}
                <text
                  x={groupX + groupW / 2}
                  y={bottomY + 14}
                  className={styles.catLabel}
                  textAnchor="middle"
                >
                  {cat}
                </text>
              </g>
            )
          }

          // Grouped
          const barW = groupW / series.length
          return (
            <g key={cat}>
              {series.map((s, si) => {
                const pt = s.data.find((d) => d.x === cat)
                const val = pt?.y ?? 0
                const barH = (val / maxY) * plotH
                const color = s.color ?? CHART_COLORS[si % CHART_COLORS.length]
                return (
                  <rect
                    key={si}
                    x={groupX + si * barW}
                    y={toY(val)}
                    width={barW - 1}
                    height={barH}
                    fill={color}
                    className={styles.bar}
                    onMouseEnter={(e) => showBarTooltip(e, cat)}
                  />
                )
              })}
              <text
                x={groupX + groupW / 2}
                y={bottomY + 14}
                className={styles.catLabel}
                textAnchor="middle"
              >
                {cat}
              </text>
            </g>
          )
        })}
      </svg>

      {/* Tooltip */}
      {tooltip && (
        <div
          className={styles.tooltip}
          style={{ left: tooltip.x + 12, top: tooltip.y }}
        >
          <div className={styles.tooltipTitle}>{tooltip.label}</div>
          {tooltip.values.map((v) => (
            <div key={v.series} className={styles.tooltipRow}>
              <span className={styles.tooltipDot} style={{ background: v.color }} />
              <span className={styles.tooltipLabel}>{v.series}:</span>
              <span className={styles.tooltipValue}>{formatAxisLabel(v.value)}</span>
            </div>
          ))}
        </div>
      )}

      {/* Legend */}
      {series.length > 1 && (
        <div className={styles.legend}>
          {series.map((s, i) => (
            <div key={s.label} className={styles.legendItem}>
              <span
                className={styles.legendDot}
                style={{ background: s.color ?? CHART_COLORS[i % CHART_COLORS.length] }}
              />
              <span className={styles.legendLabel}>{s.label}</span>
            </div>
          ))}
        </div>
      )}

      {xLabel && <div className={styles.xLabel}>{xLabel}</div>}
    </div>
  )
}
