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

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

export interface PieDatum {
  label: string;
  value: number;
  color?: string;
}

export interface PieChartProps {
  data: PieDatum[];
  width?: number;
  height?: number;
  /** Inner radius as fraction of outer radius. 0 = solid pie, 0.6 = donut. */
  innerRadiusRatio?: number;
}

const DEFAULT_PALETTE = [
  PDF_TOKENS.colors.accentBlue,
  PDF_TOKENS.colors.success,
  PDF_TOKENS.colors.warning,
  PDF_TOKENS.colors.danger,
  PDF_TOKENS.colors.accentSlate,
  '#7c3aed',
  '#0891b2',
  '#db2777',
];

export function PieChart({ data, width = 240, height = 200, innerRadiusRatio = 0 }: PieChartProps) {
  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 total = data.reduce((sum, d) => sum + d.value, 0);
  if (total === 0) {
    return (
      <Svg width={width} height={height}>
        <SvgLabel
          x={width / 2}
          y={height / 2}
          textAnchor="middle"
          fontSize={9}
          fill={PDF_TOKENS.colors.textMuted}
        >
          All zero
        </SvgLabel>
      </Svg>
    );
  }
  const chartSize = Math.min(width * 0.55, height - 30);
  const r = chartSize / 2;
  const cx = r + 12;
  const cy = height / 2;
  const ir = r * innerRadiusRatio;

  // Cumulative angle via reduce instead of a let-mutation: the
  // React Compiler safety rules forbid render-phase re-assignment
  // because it'd defeat memoization once the component is compiled.
  const slices = data.reduce<
    Array<{
      d: (typeof data)[number];
      color: string;
      startAngle: number;
      endAngle: number;
      slice: number;
    }>
  >((acc, d, i) => {
    const startAngle =
      acc.length === 0 ? -Math.PI / 2 : (acc[acc.length - 1]?.endAngle ?? -Math.PI / 2);
    const slice = (d.value / total) * Math.PI * 2;
    const endAngle = startAngle + slice;
    const color =
      d.color ?? DEFAULT_PALETTE[i % DEFAULT_PALETTE.length] ?? PDF_TOKENS.colors.accentBlue;
    acc.push({ d, color, startAngle, endAngle, slice });
    return acc;
  }, []);

  const legendX = cx + r + 24;
  const legendStartY = cy - (data.length * 12) / 2;

  return (
    <Svg width={width} height={height}>
      {slices.map((s, i) => (
        <Path key={i} d={arcPath(cx, cy, r, ir, s.startAngle, s.endAngle)} fill={s.color} />
      ))}
      {slices.map((s, i) => (
        <Svg key={`l${i}`}>
          <Rect x={legendX} y={legendStartY + i * 12 - 5} width={8} height={8} fill={s.color} />
          <SvgLabel
            x={legendX + 12}
            y={legendStartY + i * 12 + 1}
            fontSize={8}
            fill={PDF_TOKENS.colors.text}
          >
            {s.d.label}
          </SvgLabel>
          <SvgLabel
            x={legendX + 12}
            y={legendStartY + i * 12 + 10}
            fontSize={7}
            fill={PDF_TOKENS.colors.textMuted}
          >
            {Math.round((s.d.value / total) * 100)}% · {s.d.value.toLocaleString()}
          </SvgLabel>
        </Svg>
      ))}
    </Svg>
  );
}

function arcPath(
  cx: number,
  cy: number,
  outerR: number,
  innerR: number,
  startAngle: number,
  endAngle: number,
): string {
  const x1 = cx + outerR * Math.cos(startAngle);
  const y1 = cy + outerR * Math.sin(startAngle);
  const x2 = cx + outerR * Math.cos(endAngle);
  const y2 = cy + outerR * Math.sin(endAngle);
  const large = endAngle - startAngle > Math.PI ? 1 : 0;
  if (innerR === 0) {
    return `M ${cx} ${cy} L ${x1} ${y1} A ${outerR} ${outerR} 0 ${large} 1 ${x2} ${y2} Z`;
  }
  const x3 = cx + innerR * Math.cos(endAngle);
  const y3 = cy + innerR * Math.sin(endAngle);
  const x4 = cx + innerR * Math.cos(startAngle);
  const y4 = cy + innerR * Math.sin(startAngle);
  return [
    `M ${x1} ${y1}`,
    `A ${outerR} ${outerR} 0 ${large} 1 ${x2} ${y2}`,
    `L ${x3} ${y3}`,
    `A ${innerR} ${innerR} 0 ${large} 0 ${x4} ${y4}`,
    `Z`,
  ].join(' ');
}
