import {
  colors
} from "./chunk-JF3P66JF.js";
import {
  cn
} from "./chunk-P6GUNIAE.js";

// src/components/chart/chart-container.tsx
import { ResponsiveContainer } from "recharts";
import { jsx } from "react/jsx-runtime";
function ChartContainer({
  children,
  height = 320,
  width = "100%",
  className,
  style
}) {
  return /* @__PURE__ */ jsx("div", { className: cn("text-xs text-foreground", className), style: { width, height, ...style }, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children }) });
}

// src/components/chart/chart-legend-content.tsx
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
function ChartLegendContent({ payload, className, iconType = "square" }) {
  if (!payload || payload.length === 0) return null;
  return /* @__PURE__ */ jsx2(
    "ul",
    {
      className: cn("flex flex-wrap items-center justify-center gap-x-4 gap-y-2 text-xs text-brown-80", className),
      children: payload.map((entry, i) => {
        const swatchColor = typeof entry.color === "string" ? entry.color : "transparent";
        const label = entry.value !== void 0 ? String(entry.value) : "";
        return /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1.5", children: [
          iconType === "square" ? /* @__PURE__ */ jsx2("span", { className: "inline-block h-2.5 w-2.5 shrink-0 rounded-sm", style: { background: swatchColor } }) : /* @__PURE__ */ jsx2("span", { className: "inline-block h-[3px] w-4 shrink-0 rounded-full", style: { background: swatchColor } }),
          /* @__PURE__ */ jsx2("span", { children: label })
        ] }, `${label}-${i}`);
      })
    }
  );
}

// src/components/chart/chart-tooltip-content.tsx
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
function ChartTooltipContent({
  active,
  payload,
  label,
  className,
  showLabel = true,
  formatValue
}) {
  if (!active || !payload || payload.length === 0) return null;
  return /* @__PURE__ */ jsxs2(
    "div",
    {
      className: cn(
        "rounded-lg border border-brown-40 bg-brown-10 px-3 py-2 text-xs shadow-sm",
        "min-w-32 text-foreground",
        className
      ),
      children: [
        showLabel && label !== void 0 && label !== null ? /* @__PURE__ */ jsx3("div", { className: "mb-1.5 font-medium text-brown-90", children: String(label) }) : null,
        /* @__PURE__ */ jsx3("ul", { className: "space-y-1", children: payload.map((entry, i) => {
          const name = entry.name !== void 0 ? String(entry.name) : "";
          const rawValue = entry.value;
          const display = formatValue ? formatValue(rawValue, name) : rawValue === void 0 ? "" : String(rawValue);
          const swatch = typeof entry.color === "string" ? entry.color : "transparent";
          return /* @__PURE__ */ jsxs2("li", { className: "flex items-center gap-2", children: [
            /* @__PURE__ */ jsx3("span", { className: "inline-block h-2.5 w-2.5 shrink-0 rounded-sm", style: { background: swatch } }),
            /* @__PURE__ */ jsx3("span", { className: "text-brown-70", children: name }),
            /* @__PURE__ */ jsx3("span", { className: "ml-auto font-semibold tabular-nums text-brown-90", children: display })
          ] }, `${name}-${i}`);
        }) })
      ]
    }
  );
}

// src/components/chart/chart-palette.ts
var CHART_PALETTE = [
  colors["blue-600"],
  //   #2563EB  — primary
  colors["blue-400"],
  //   #60A5FA  — mid
  colors["blue-300"],
  //   #93C5FD  — light
  colors["blue-100"],
  //   #DBEAFE  — very light
  colors["indigo-400"],
  // #818CF8
  colors["indigo-500"],
  // #6366F1
  colors["indigo-600"],
  // #4F46E5
  colors["indigo-800"],
  // #3730A3
  colors["blue-800"]
  //   #1E40AF  — deepest
];
var OTHERS_SLICE_COLOR = colors["brown-60"];
var DEFAULT_OTHERS_CATEGORY_LABELS = ["others", "other"];
function isOthersCategory(value, labels) {
  if (value === null || value === void 0) return false;
  if (labels.length === 0) return false;
  const normalized = String(value).trim().toLowerCase();
  for (const label of labels) {
    if (normalized === label.toLowerCase()) return true;
  }
  return false;
}
function colorForSeriesIndex(index, palette = CHART_PALETTE) {
  return palette[index % palette.length] ?? CHART_PALETTE[0];
}

// src/components/chart/chart-styles.ts
var GRID_STROKE = colors["brown-40"];
var AXIS_STROKE = colors["brown-50"];
var AXIS_TICK_STYLE = {
  fill: colors["brown-70"],
  fontSize: 12,
  fontWeight: 500
};
var CHART_VALUE_LABEL_STYLE = {
  fill: colors["brown-70"],
  fontSize: 12,
  fontWeight: 500
};
var BAR_TOOLTIP_CURSOR_FILL = colors["brown-alpha-12"];
var LINE_ACTIVE_DOT_STROKE = colors["brown-10"];
var CHART_MARGIN = { top: 8, right: 16, left: 0, bottom: 4 };
var PIE_CHART_MARGIN = { top: 0, right: 24, left: 24, bottom: 4 };
var CHART_AXIS_PROPS = {
  stroke: AXIS_STROKE,
  tick: AXIS_TICK_STYLE,
  tickLine: false,
  axisLine: false
};
var CHART_GRID_PROPS = {
  stroke: GRID_STROKE,
  strokeDasharray: "3 3",
  vertical: false
};

// src/components/chart/coerce-numeric.ts
function coerceNumericColumns(rows, numericKeys) {
  return rows.map((row) => {
    const out = { ...row };
    for (const k of numericKeys) {
      const v = out[k];
      if (v == null) continue;
      const n = Number(v);
      out[k] = Number.isFinite(n) ? n : NaN;
    }
    return out;
  });
}

// src/components/chart/bar-chart/bar-chart.tsx
import { useMemo } from "react";
import { Bar, BarChart as RechartsBarChart, CartesianGrid, LabelList, Legend, Tooltip, XAxis, YAxis } from "recharts";

// src/components/chart/chart-tick-utils.ts
function maxTickCharsByCategoryCount(n) {
  if (n <= 5) return 24;
  if (n <= 8) return 14;
  if (n <= 12) return 10;
  if (n <= 16) return 7;
  return 5;
}
function truncateLabel(value, maxChars) {
  const s = String(value ?? "");
  if (s.length <= maxChars) return s;
  return s.slice(0, Math.max(1, maxChars - 1)).trimEnd() + "\u2026";
}
function evenlyDistributedVisibleIndices(n, target) {
  if (n <= target) {
    return new Set(Array.from({ length: n }, (_, i) => i));
  }
  const set = /* @__PURE__ */ new Set();
  const step = (n - 1) / (target - 1);
  for (let i = 0; i < target; i++) {
    set.add(Math.round(i * step));
  }
  return set;
}
function defaultBarTickFormatter(categoryCount) {
  const max = maxTickCharsByCategoryCount(categoryCount);
  return (value) => truncateLabel(value, max);
}
function defaultLineChartTickFormatter(categoryCount, visibleIndices) {
  const max = maxTickCharsByCategoryCount(visibleIndices.size || categoryCount);
  return (value, index) => {
    if (!visibleIndices.has(index)) return "";
    return truncateLabel(value, max);
  };
}

// src/components/chart/bar-chart/bar-chart.tsx
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
function BarChart({
  data,
  xKey,
  series,
  stacked = false,
  height = 320,
  width = "100%",
  className,
  palette = CHART_PALETTE,
  showTooltip = true,
  showLegend,
  showGrid = true,
  showXAxis = true,
  showYAxis = true,
  showValueLabels,
  xAxisInterval = 0,
  xAxisAngle,
  xAxisTickFormatter
}) {
  const seriesKeys = useMemo(() => series.map((s) => s.key), [series]);
  const coercedData = useMemo(
    () => coerceNumericColumns(data, seriesKeys),
    [data, seriesKeys]
  );
  const resolvedShowLegend = showLegend ?? series.length > 1;
  const resolvedShowValueLabels = showValueLabels ?? (!stacked && series.length === 1);
  const resolvedAngle = xAxisAngle ?? (coercedData.length >= 8 ? -30 : 0);
  const resolvedTickFormatter = useMemo(
    () => xAxisTickFormatter ?? defaultBarTickFormatter(coercedData.length),
    [xAxisTickFormatter, coercedData.length]
  );
  const angledLabelPad = resolvedAngle === 0 ? 0 : Math.min(Math.abs(resolvedAngle) * 0.7, 40);
  const chartMargin = { ...CHART_MARGIN, bottom: CHART_MARGIN.bottom + angledLabelPad };
  return /* @__PURE__ */ jsx4(ChartContainer, { height, width, className, children: /* @__PURE__ */ jsxs3(RechartsBarChart, { data: coercedData, margin: chartMargin, barCategoryGap: "22%", children: [
    showGrid ? /* @__PURE__ */ jsx4(CartesianGrid, { ...CHART_GRID_PROPS }) : null,
    showXAxis ? /* @__PURE__ */ jsx4(
      XAxis,
      {
        dataKey: xKey,
        ...CHART_AXIS_PROPS,
        interval: xAxisInterval,
        angle: resolvedAngle,
        textAnchor: resolvedAngle !== 0 ? "end" : "middle",
        tickMargin: resolvedAngle === 0 ? 8 : 12,
        height: resolvedAngle !== 0 ? 60 : void 0,
        tickFormatter: resolvedTickFormatter
      }
    ) : null,
    showYAxis ? /* @__PURE__ */ jsx4(YAxis, { ...CHART_AXIS_PROPS, width: 40 }) : null,
    showTooltip ? /* @__PURE__ */ jsx4(Tooltip, { cursor: { fill: BAR_TOOLTIP_CURSOR_FILL }, content: /* @__PURE__ */ jsx4(ChartTooltipContent, {}) }) : null,
    resolvedShowLegend ? /* @__PURE__ */ jsx4(
      Legend,
      {
        verticalAlign: "top",
        align: "center",
        wrapperStyle: { top: 0 },
        itemSorter: null,
        content: /* @__PURE__ */ jsx4(ChartLegendContent, { iconType: "square" })
      }
    ) : null,
    series.map((s, i) => /* @__PURE__ */ jsx4(
      Bar,
      {
        dataKey: s.key,
        name: s.label,
        fill: colorForSeriesIndex(i, palette),
        stackId: stacked ? "default" : s.key,
        radius: barRadius(stacked, i, series.length),
        children: resolvedShowValueLabels ? /* @__PURE__ */ jsx4(LabelList, { dataKey: s.key, position: "top", style: CHART_VALUE_LABEL_STYLE }) : null
      },
      s.key
    ))
  ] }) });
}
function barRadius(stacked, seriesIndex, seriesCount) {
  if (!stacked) return [6, 6, 0, 0];
  const isTopSegment = seriesIndex === seriesCount - 1;
  return isTopSegment ? [6, 6, 0, 0] : [0, 0, 0, 0];
}

// src/components/chart/line-chart/line-chart.tsx
import { useMemo as useMemo2 } from "react";
import {
  CartesianGrid as CartesianGrid2,
  LabelList as LabelList2,
  Legend as Legend2,
  Line,
  LineChart as RechartsLineChart,
  Tooltip as Tooltip2,
  XAxis as XAxis2,
  YAxis as YAxis2
} from "recharts";
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
var TARGET_VISIBLE_LABELS = 5;
function LineChart({
  data,
  xKey,
  series,
  smooth = true,
  showDots = true,
  strokeWidth = 2,
  height = 320,
  width = "100%",
  className,
  palette = CHART_PALETTE,
  showTooltip = true,
  showLegend,
  showGrid = true,
  showXAxis = true,
  showYAxis = true,
  showValueLabels = false,
  xAxisInterval = 0,
  xAxisAngle = 0,
  xAxisTickFormatter
}) {
  const seriesKeys = useMemo2(() => series.map((s) => s.key), [series]);
  const coercedData = useMemo2(
    () => coerceNumericColumns(data, seriesKeys),
    [data, seriesKeys]
  );
  const lineType = smooth ? "monotone" : "linear";
  const resolvedShowLegend = showLegend ?? series.length > 1;
  const resolvedTickFormatter = useMemo2(() => {
    if (xAxisTickFormatter) return xAxisTickFormatter;
    const visible = evenlyDistributedVisibleIndices(coercedData.length, TARGET_VISIBLE_LABELS);
    return defaultLineChartTickFormatter(coercedData.length, visible);
  }, [xAxisTickFormatter, coercedData.length]);
  const angledLabelPad = xAxisAngle === 0 ? 0 : Math.min(Math.abs(xAxisAngle) * 0.7, 40);
  const chartMargin = { ...CHART_MARGIN, right: CHART_MARGIN.right + 16, bottom: CHART_MARGIN.bottom + angledLabelPad };
  return /* @__PURE__ */ jsx5(ChartContainer, { height, width, className, children: /* @__PURE__ */ jsxs4(RechartsLineChart, { data: coercedData, margin: chartMargin, children: [
    showGrid ? /* @__PURE__ */ jsx5(CartesianGrid2, { ...CHART_GRID_PROPS }) : null,
    showXAxis ? /* @__PURE__ */ jsx5(
      XAxis2,
      {
        dataKey: xKey,
        ...CHART_AXIS_PROPS,
        interval: xAxisInterval,
        angle: xAxisAngle,
        textAnchor: xAxisAngle !== 0 ? "end" : "middle",
        tickMargin: xAxisAngle === 0 ? 8 : 12,
        height: xAxisAngle !== 0 ? 60 : void 0,
        tickFormatter: resolvedTickFormatter
      }
    ) : null,
    showYAxis ? /* @__PURE__ */ jsx5(YAxis2, { ...CHART_AXIS_PROPS, width: 40 }) : null,
    showTooltip ? /* @__PURE__ */ jsx5(Tooltip2, { content: /* @__PURE__ */ jsx5(ChartTooltipContent, {}) }) : null,
    resolvedShowLegend ? /* @__PURE__ */ jsx5(
      Legend2,
      {
        verticalAlign: "top",
        align: "center",
        wrapperStyle: { top: 0 },
        itemSorter: null,
        content: /* @__PURE__ */ jsx5(ChartLegendContent, { iconType: "line" })
      }
    ) : null,
    series.map((s, i) => {
      const color = colorForSeriesIndex(i, palette);
      return /* @__PURE__ */ jsx5(
        Line,
        {
          type: lineType,
          dataKey: s.key,
          name: s.label,
          stroke: color,
          strokeWidth,
          dot: showDots ? { r: 3, fill: color, stroke: color, strokeWidth: 0 } : false,
          activeDot: { r: 5, fill: color, stroke: LINE_ACTIVE_DOT_STROKE, strokeWidth: 2 },
          children: showValueLabels ? /* @__PURE__ */ jsx5(LabelList2, { dataKey: s.key, position: "top", style: CHART_VALUE_LABEL_STYLE }) : null
        },
        s.key
      );
    })
  ] }) });
}

// src/components/chart/pie-chart/pie-chart.tsx
import { useMemo as useMemo3 } from "react";
import { Cell, Legend as Legend3, Pie, PieChart as RechartsPieChart, Tooltip as Tooltip3 } from "recharts";
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
function PieChart({
  data,
  categoryKey,
  valueKey,
  height = 320,
  width = "100%",
  className,
  palette = CHART_PALETTE,
  showLabels = true,
  showTooltip = true,
  showLegend = true,
  innerRadius = 0,
  outerRadius = "68%",
  othersCategoryLabels = DEFAULT_OTHERS_CATEGORY_LABELS
}) {
  const { orderedData, sliceColors } = useMemo3(() => {
    const coerced = coerceNumericColumns(data, [valueKey]);
    const namedRows = [];
    const namedColors = [];
    const othersRows = [];
    const othersColors = [];
    for (const row of coerced) {
      if (isOthersCategory(row[categoryKey], othersCategoryLabels)) {
        othersRows.push(row);
        othersColors.push(OTHERS_SLICE_COLOR);
      } else {
        namedRows.push(row);
        namedColors.push(colorForSeriesIndex(namedRows.length - 1, palette));
      }
    }
    return {
      orderedData: [...namedRows, ...othersRows],
      sliceColors: [...namedColors, ...othersColors]
    };
  }, [data, valueKey, categoryKey, othersCategoryLabels, palette]);
  return /* @__PURE__ */ jsx6(ChartContainer, { height, width, className, children: /* @__PURE__ */ jsxs5(RechartsPieChart, { margin: PIE_CHART_MARGIN, children: [
    showTooltip ? /* @__PURE__ */ jsx6(Tooltip3, { content: /* @__PURE__ */ jsx6(ChartTooltipContent, {}) }) : null,
    showLegend ? /* @__PURE__ */ jsx6(
      Legend3,
      {
        verticalAlign: "top",
        align: "center",
        wrapperStyle: { top: 0 },
        itemSorter: null,
        content: /* @__PURE__ */ jsx6(ChartLegendContent, { iconType: "square" })
      }
    ) : null,
    /* @__PURE__ */ jsx6(
      Pie,
      {
        data: orderedData,
        dataKey: valueKey,
        nameKey: categoryKey,
        cx: "50%",
        cy: "52%",
        startAngle: 90,
        endAngle: -270,
        innerRadius,
        outerRadius,
        label: showLabels ? (entry) => {
          const v = entry.value;
          if (v === void 0 || v === null) return null;
          return /* @__PURE__ */ jsx6(
            "text",
            {
              x: entry.x,
              y: entry.y,
              fill: CHART_VALUE_LABEL_STYLE.fill,
              fontSize: CHART_VALUE_LABEL_STYLE.fontSize,
              fontWeight: CHART_VALUE_LABEL_STYLE.fontWeight,
              textAnchor: entry.textAnchor,
              dominantBaseline: "central",
              children: String(v)
            }
          );
        } : false,
        labelLine: false,
        stroke: "none",
        strokeWidth: 0,
        children: orderedData.map((_row, i) => /* @__PURE__ */ jsx6(Cell, { fill: sliceColors[i] }, i))
      }
    )
  ] }) });
}

export {
  ChartContainer,
  ChartLegendContent,
  ChartTooltipContent,
  CHART_PALETTE,
  colorForSeriesIndex,
  CHART_AXIS_PROPS,
  CHART_GRID_PROPS,
  coerceNumericColumns,
  BarChart,
  LineChart,
  PieChart
};
//# sourceMappingURL=chunk-YZB6YXKK.js.map