{"version":3,"sources":["../src/components/ProficiencyChart/ProficiencyChart.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\nimport type {\n  ProficiencyCounters,\n  ProficiencyChartProps,\n  SliceData,\n  PieChartProps,\n} from './interfaces';\n\nexport type { ProficiencyCounters, ProficiencyChartProps } from './interfaces';\n\n/**\n * Build slices from counters\n */\nconst buildSlices = (\n  counters: ProficiencyCounters,\n  total: number\n): SliceData[] => {\n  if (total === 0) return [];\n\n  return [\n    {\n      key: 'attentionPoint',\n      label: 'Ponto de atenção',\n      value: counters.attentionPoint,\n      percentage: (counters.attentionPoint / total) * 100,\n      colorClass: 'bg-error-600',\n      fillColor: '#dc2626', // error-600\n    },\n    {\n      key: 'belowAverage',\n      label: 'Abaixo da média',\n      value: counters.belowAverage,\n      percentage: (counters.belowAverage / total) * 100,\n      colorClass: 'bg-warning-400',\n      fillColor: '#fbbf24', // warning-400\n    },\n    {\n      key: 'aboveAverage',\n      label: 'Acima da média',\n      value: counters.aboveAverage,\n      percentage: (counters.aboveAverage / total) * 100,\n      colorClass: 'bg-success-400',\n      fillColor: '#4ade80', // success-400\n    },\n    {\n      key: 'highlight',\n      label: 'Destaque da turma',\n      value: counters.highlight,\n      percentage: (counters.highlight / total) * 100,\n      colorClass: 'bg-success-700',\n      fillColor: '#15803d', // success-700\n    },\n  ];\n};\n\n/** SVG viewBox size */\nconst CHART_SIZE = 180;\n\n/**\n * Simple pie chart sub-component\n */\nconst PieChart = ({\n  slices,\n  hoveredSlice,\n  onSliceHover,\n}: Readonly<PieChartProps>) => {\n  const total = slices.reduce((sum, s) => sum + s.value, 0);\n  if (total === 0) {\n    return (\n      <div className=\"flex items-center justify-center w-[180px] h-[180px] bg-background-50 rounded-full\">\n        <Text size=\"sm\" className=\"text-text-500\">\n          Sem dados\n        </Text>\n      </div>\n    );\n  }\n\n  const cx = CHART_SIZE / 2;\n  const cy = CHART_SIZE / 2;\n  const radius = CHART_SIZE / 2 - 5;\n\n  let cumulativePercent = 0;\n\n  const paths = slices.map((slice) => {\n    const percent = slice.percentage;\n    const startPercent = cumulativePercent;\n    cumulativePercent += percent;\n\n    if (percent === 0) return null;\n\n    const startAngle = (startPercent / 100) * 360 - 90;\n    const endAngle = ((startPercent + percent) / 100) * 360 - 90;\n\n    const startRad = (startAngle * Math.PI) / 180;\n    const endRad = (endAngle * Math.PI) / 180;\n\n    const x1 = cx + radius * Math.cos(startRad);\n    const y1 = cy + radius * Math.sin(startRad);\n    const x2 = cx + radius * Math.cos(endRad);\n    const y2 = cy + radius * Math.sin(endRad);\n\n    const largeArc = percent > 50 ? 1 : 0;\n\n    // Handle full circle case\n    const d =\n      percent >= 100\n        ? `M ${cx - radius} ${cy} A ${radius} ${radius} 0 1 1 ${cx + radius} ${cy} A ${radius} ${radius} 0 1 1 ${cx - radius} ${cy}`\n        : `M ${cx} ${cy} L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2} Z`;\n\n    // Calculate label position (center of slice)\n    const midAngle = ((startPercent + percent / 2) / 100) * 360 - 90;\n    const midRad = (midAngle * Math.PI) / 180;\n    const labelRadius = radius * 0.65;\n    const labelX = cx + labelRadius * Math.cos(midRad);\n    const labelY = cy + labelRadius * Math.sin(midRad);\n\n    const isOtherHovered = hoveredSlice && hoveredSlice !== slice.key;\n\n    return (\n      <g key={slice.key}>\n        <path\n          d={d}\n          className=\"cursor-pointer transition-opacity\"\n          style={{ fill: slice.fillColor, opacity: isOtherHovered ? 0.3 : 1 }}\n          onMouseEnter={() => onSliceHover(slice.key)}\n          onMouseLeave={() => onSliceHover(null)}\n        />\n        {/* Label inside slice (only if percentage > 8%) */}\n        {percent >= 8 && (\n          <text\n            x={labelX}\n            y={labelY}\n            textAnchor=\"middle\"\n            dominantBaseline=\"middle\"\n            className=\"fill-white text-xs font-semibold pointer-events-none\"\n            style={{\n              textShadow: '0 1px 2px rgba(0,0,0,0.3)',\n              opacity: isOtherHovered ? 0.3 : 1,\n            }}\n          >\n            {slice.percentage.toFixed(0)}%\n          </text>\n        )}\n      </g>\n    );\n  });\n\n  return (\n    <svg\n      viewBox={`0 0 ${CHART_SIZE} ${CHART_SIZE}`}\n      className=\"w-[180px] h-[180px]\"\n    >\n      {paths}\n    </svg>\n  );\n};\n\n/**\n * ProficiencyChart - displays a pie chart showing the distribution of student proficiency levels.\n *\n * @example\n * ```tsx\n * <ProficiencyChart\n *   counters={{\n *     highlight: 10,\n *     aboveAverage: 25,\n *     belowAverage: 15,\n *     attentionPoint: 5,\n *   }}\n *   totalStudents={55}\n * />\n * ```\n */\nexport const ProficiencyChart = ({\n  counters,\n  totalStudents,\n  className,\n  ...props\n}: Readonly<ProficiencyChartProps>) => {\n  const [hoveredSlice, setHoveredSlice] = useState<string | null>(null);\n\n  const total = totalStudents ?? 0;\n\n  const slices = useMemo(() => {\n    if (!counters) return [];\n    return buildSlices(counters, total);\n  }, [counters, total]);\n\n  if (!counters || total === 0) {\n    return (\n      <div\n        className={cn(\n          'flex items-center justify-center h-[200px] bg-background border border-border-50 rounded-xl',\n          className\n        )}\n        {...props}\n      >\n        <Text size=\"sm\" className=\"text-text-500\">\n          Sem dados de proficiência disponíveis\n        </Text>\n      </div>\n    );\n  }\n\n  return (\n    <div\n      className={cn(\n        'w-full bg-background border border-border-50 rounded-xl p-5',\n        className\n      )}\n      {...props}\n    >\n      <Text as=\"h3\" size=\"md\" weight=\"semibold\" className=\"text-text-950 mb-4\">\n        Proficiência por quantidade de estudante\n      </Text>\n\n      <div className=\"flex items-center justify-between gap-6\">\n        {/* Legend */}\n        <div className=\"flex flex-col gap-3\">\n          {slices.map((slice) => (\n            <div\n              key={slice.key}\n              className={cn(\n                'flex items-center gap-3 cursor-pointer transition-opacity',\n                hoveredSlice && hoveredSlice !== slice.key && 'opacity-50'\n              )}\n              onMouseEnter={() => setHoveredSlice(slice.key)}\n              onMouseLeave={() => setHoveredSlice(null)}\n            >\n              <span\n                className={cn(\n                  'w-3 h-3 rounded-full shrink-0',\n                  slice.colorClass\n                )}\n              />\n              <div className=\"flex flex-col\">\n                <Text size=\"sm\" weight=\"medium\" className=\"text-text-950\">\n                  {slice.label}\n                </Text>\n                <Text size=\"xs\" className=\"text-text-500\">\n                  {slice.value.toLocaleString('pt-BR')}{' '}\n                  {slice.value === 1 ? 'aluno' : 'alunos'} (\n                  {slice.percentage.toFixed(1)}%)\n                </Text>\n              </div>\n            </div>\n          ))}\n\n          {/* Total */}\n          <div className=\"pt-2 border-t border-border-100\">\n            <Text size=\"sm\" weight=\"semibold\" className=\"text-text-950\">\n              Total: {total.toLocaleString('pt-BR')}{' '}\n              {total === 1 ? 'aluno' : 'alunos'}\n            </Text>\n          </div>\n        </div>\n\n        {/* Pie Chart */}\n        <div className=\"shrink-0\">\n          <PieChart\n            slices={slices}\n            hoveredSlice={hoveredSlice}\n            onSliceHover={setHoveredSlice}\n          />\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default ProficiencyChart;\n"],"mappings":"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","names":[]}