import { Line, Rect, Svg } from '@react-pdf/renderer';

import { SvgLabel } from '../svg-primitives';
import { PDF_TOKENS } from '../tokens';

export interface BarDatum {
  label: string;
  value: number;
  /** Optional override color per bar. */
  color?: string;
}

export interface BarChartProps {
  data: BarDatum[];
  width?: number;
  height?: number;
  /** Bar fill when not overridden per-datum. */
  color?: string;
  /** Render value labels on top of each bar. */
  showValues?: boolean;
  /** Optional y-axis label rendered vertically on the left. */
  yLabel?: string;
}

const MARGIN_LEFT = 44;
const MARGIN_RIGHT = 12;
const MARGIN_TOP = 18;
const MARGIN_BOTTOM = 32;

export function BarChart({
  data,
  width = 480,
  height = 200,
  color = PDF_TOKENS.colors.accentBlue,
  showValues = false,
  yLabel,
}: BarChartProps) {
  if (data.length === 0) {
    return (
      <Svg width={width} height={height}>
        <SvgLabel
          x={width / 2}
          y={height / 2}
          textAnchor="middle"
          fontSize={9}
          fill={PDF_TOKENS.colors.textMuted}
        >
          No data
        </SvgLabel>
      </Svg>
    );
  }
  const max = Math.max(...data.map((d) => d.value));
  const chartW = width - MARGIN_LEFT - MARGIN_RIGHT;
  const chartH = height - MARGIN_TOP - MARGIN_BOTTOM;
  const barW = chartW / data.length;
  const yTicks = 4;
  return (
    <Svg width={width} height={height}>
      {/* y-axis tick labels + horizontal grid */}
      {Array.from({ length: yTicks + 1 }, (_, i) => {
        const v = (max / yTicks) * (yTicks - i);
        const y = MARGIN_TOP + (chartH / yTicks) * i;
        return (
          <Svg key={`t${i}`}>
            <Line
              x1={MARGIN_LEFT}
              y1={y}
              x2={width - MARGIN_RIGHT}
              y2={y}
              strokeWidth={0.5}
              stroke={PDF_TOKENS.colors.border}
            />
            <SvgLabel
              x={MARGIN_LEFT - 6}
              y={y + 3}
              textAnchor="end"
              fontSize={7}
              fill={PDF_TOKENS.colors.textMuted}
            >
              {formatTick(v)}
            </SvgLabel>
          </Svg>
        );
      })}
      {/* axes */}
      <Line
        x1={MARGIN_LEFT}
        y1={MARGIN_TOP}
        x2={MARGIN_LEFT}
        y2={height - MARGIN_BOTTOM}
        strokeWidth={1}
        stroke={PDF_TOKENS.colors.text}
      />
      <Line
        x1={MARGIN_LEFT}
        y1={height - MARGIN_BOTTOM}
        x2={width - MARGIN_RIGHT}
        y2={height - MARGIN_BOTTOM}
        strokeWidth={1}
        stroke={PDF_TOKENS.colors.text}
      />
      {/* bars + labels */}
      {data.map((d, i) => {
        const h = max === 0 ? 0 : (d.value / max) * chartH;
        const x = MARGIN_LEFT + i * barW + 4;
        const y = height - MARGIN_BOTTOM - h;
        const w = barW - 8;
        return (
          <Svg key={i}>
            <Rect x={x} y={y} width={w} height={h} fill={d.color ?? color} />
            <SvgLabel
              x={x + w / 2}
              y={height - MARGIN_BOTTOM + 14}
              textAnchor="middle"
              fontSize={7}
              fill={PDF_TOKENS.colors.textMuted}
            >
              {d.label}
            </SvgLabel>
            {showValues ? (
              <SvgLabel
                x={x + w / 2}
                y={y - 3}
                textAnchor="middle"
                fontSize={7}
                fill={PDF_TOKENS.colors.text}
              >
                {formatTick(d.value)}
              </SvgLabel>
            ) : null}
          </Svg>
        );
      })}
      {yLabel ? (
        <SvgLabel
          x={10}
          y={MARGIN_TOP + chartH / 2}
          textAnchor="middle"
          fontSize={8}
          fill={PDF_TOKENS.colors.textMuted}
          transform={`rotate(-90 10 ${MARGIN_TOP + chartH / 2})`}
        >
          {yLabel}
        </SvgLabel>
      ) : null}
    </Svg>
  );
}

function formatTick(v: number): string {
  if (v >= 1_000_000) return `${(v / 1_000_000).toFixed(1)}M`;
  if (v >= 1_000) return `${(v / 1_000).toFixed(1)}k`;
  return v.toLocaleString();
}
