// Bar chart SVG générique :
//  - orientation = vertical | horizontal
//  - mode        = simple | grouped | stacked
// Chaque data point a un label + N valeurs (1 par série). Pas d'axes
// numériques pour rester lisible compact ; les valeurs absolues s'affichent
// au survol via <title> ou en option via showValues.

type Series = {
  name: string;
  color?: string;
};

type DataPoint = {
  label: string;
  values: number[];
};

type Props = {
  data: DataPoint[];
  series: Series[];
  orientation?: "vertical" | "horizontal";
  mode?: "simple" | "grouped" | "stacked";
  /** Hauteur (vertical) ou hauteur ligne (horizontal × nb data). Défaut adapté. */
  height?: number;
  /** Largeur fixe. Défaut auto (100%). */
  width?: number;
  /** Plafond y/x. Auto-calc si non fourni. */
  maxValue?: number;
  /** Affiche la légende en bas. */
  legend?: boolean;
  /** Affiche les valeurs au-dessus de chaque barre. */
  showValues?: boolean;
  className?: string;
  /** Format optionnel des valeurs (ex: priceFmt.format). */
  formatValue?: (v: number) => string;
};

const DEFAULT_PALETTE = [
  "var(--accent)",
  "var(--success)",
  "var(--warning)",
  "var(--danger)",
  "#a78bfa",
  "#06b6d4",
];

export function BarChart({
  data,
  series,
  orientation = "vertical",
  mode = "simple",
  height,
  width = 600,
  maxValue: maxValueProp,
  legend = true,
  showValues = false,
  className = "",
  formatValue = (v) => String(v),
}: Props) {
  // Pour mode "stacked", max = max(sum_i(values)) ; sinon max(all values)
  const maxValue =
    maxValueProp ??
    Math.max(
      1,
      ...data.flatMap((d) =>
        mode === "stacked" ? [d.values.reduce((s, v) => s + v, 0)] : d.values,
      ),
    );

  const seriesWithColor = series.map((s, i) => ({
    ...s,
    color: s.color ?? DEFAULT_PALETTE[i % DEFAULT_PALETTE.length],
  }));

  if (orientation === "vertical") {
    return (
      <BarChartVertical
        data={data}
        series={seriesWithColor}
        mode={mode}
        height={height ?? 200}
        width={width}
        maxValue={maxValue}
        legend={legend}
        showValues={showValues}
        formatValue={formatValue}
        className={className}
      />
    );
  }
  return (
    <BarChartHorizontal
      data={data}
      series={seriesWithColor}
      mode={mode}
      // Hauteur minimum par ligne pour la lisibilité.
      lineHeight={height ?? 28}
      width={width}
      maxValue={maxValue}
      legend={legend}
      showValues={showValues}
      formatValue={formatValue}
      className={className}
    />
  );
}

// ─── Vertical ───────────────────────────────────────────────────────────

function BarChartVertical({
  data,
  series,
  mode,
  height,
  width,
  maxValue,
  legend,
  showValues,
  formatValue,
  className,
}: {
  data: DataPoint[];
  series: Array<Series & { color: string }>;
  mode: "simple" | "grouped" | "stacked";
  height: number;
  width: number;
  maxValue: number;
  legend: boolean;
  showValues: boolean;
  formatValue: (v: number) => string;
  className: string;
}) {
  // Cas dense (> 12 entrées comme les buckets horaires 24h) :
  //  - on ROTATE les labels de -45° pour qu'ils ne se chevauchent pas
  //  - on garde TOUS les labels (chaque barre est identifiable)
  //  - on rajoute des tick marks verticaux sur l'axe X pour aider l'œil
  //  - padBottom étendu pour accommoder la rotation
  const dense = data.length > 12;
  const padTop = showValues ? 18 : 4;
  const padBottom = dense ? 44 : 22;
  const chartH = height - padTop - padBottom;
  const groupW = width / Math.max(1, data.length);
  const innerPad = 0.18; // 18% de padding entre groupes
  const barTotalW = groupW * (1 - innerPad * 2);
  const groupCenter = (i: number) => groupW * (i + 0.5);
  const axisY = padTop + chartH;

  return (
    <div className={className}>
      <svg
        width="100%"
        viewBox={`0 0 ${width} ${height}`}
        preserveAspectRatio="none"
        role="img"
      >
        {/* Axe X + tick marks pour repérer chaque barre */}
        <line
          x1={0}
          x2={width}
          y1={axisY + 0.5}
          y2={axisY + 0.5}
          stroke="var(--border, #e5e7eb)"
        />
        {data.map((_, i) => {
          const cx = groupCenter(i);
          return (
            <line
              key={`tick-${i}`}
              x1={cx}
              x2={cx}
              y1={axisY}
              y2={axisY + 3}
              stroke="var(--border, #e5e7eb)"
            />
          );
        })}
        {data.map((d, i) => {
          const cx = groupCenter(i);
          const labelEl = dense ? (
            <text
              x={cx}
              y={axisY + 8}
              textAnchor="end"
              transform={`rotate(-45 ${cx} ${axisY + 8})`}
              className="fill-muted-foreground text-[10px]"
            >
              {d.label}
            </text>
          ) : (
            <text
              x={cx}
              y={height - 6}
              textAnchor="middle"
              className="fill-muted-foreground text-[10px]"
            >
              {d.label}
            </text>
          );
          if (mode === "stacked") {
            // Une seule barre, segments empilés (du bas vers le haut).
            const total = d.values.reduce((s, v) => s + v, 0);
            const totalH = (total / maxValue) * chartH;
            let yBottom = padTop + chartH;
            return (
              <g key={i}>
                {d.values.map((v, k) => {
                  const segH = (v / maxValue) * chartH;
                  const y = yBottom - segH;
                  yBottom -= segH;
                  return (
                    <rect
                      key={k}
                      x={cx - barTotalW / 2}
                      y={y}
                      width={barTotalW}
                      height={Math.max(0, segH)}
                      fill={series[k]?.color ?? "currentColor"}
                    >
                      <title>{`${series[k]?.name ?? ""} : ${formatValue(v)}`}</title>
                    </rect>
                  );
                })}
                {showValues && total > 0 && (
                  <text
                    x={cx}
                    y={padTop + chartH - totalH - 4}
                    textAnchor="middle"
                    className="fill-current text-[10px] tabular-nums"
                  >
                    {formatValue(total)}
                  </text>
                )}
                {labelEl}
              </g>
            );
          }

          // Mode simple ou grouped : N barres côte à côte.
          const nSeries = d.values.length;
          const innerGap = Math.max(1, barTotalW * 0.05);
          const barW = (barTotalW - innerGap * (nSeries - 1)) / nSeries;
          return (
            <g key={i}>
              {d.values.map((v, k) => {
                const barH = (v / maxValue) * chartH;
                const x = cx - barTotalW / 2 + k * (barW + innerGap);
                const y = padTop + chartH - barH;
                return (
                  <g key={k}>
                    <rect
                      x={x}
                      y={y}
                      width={barW}
                      height={Math.max(0, barH)}
                      fill={series[k]?.color ?? "currentColor"}
                      rx={1}
                    >
                      <title>{`${series[k]?.name ?? ""} : ${formatValue(v)}`}</title>
                    </rect>
                    {showValues && v > 0 && (
                      <text
                        x={x + barW / 2}
                        y={y - 4}
                        textAnchor="middle"
                        className="fill-current text-[10px] tabular-nums"
                      >
                        {formatValue(v)}
                      </text>
                    )}
                  </g>
                );
              })}
              {labelEl}
            </g>
          );
        })}
      </svg>
      {legend && series.length > 1 && <Legend series={series} />}
    </div>
  );
}

// ─── Horizontal (top N) ─────────────────────────────────────────────────

function BarChartHorizontal({
  data,
  series,
  mode,
  lineHeight,
  width,
  maxValue,
  legend,
  showValues,
  formatValue,
  className,
}: {
  data: DataPoint[];
  series: Array<Series & { color: string }>;
  mode: "simple" | "grouped" | "stacked";
  lineHeight: number;
  width: number;
  maxValue: number;
  legend: boolean;
  showValues: boolean;
  formatValue: (v: number) => string;
  className: string;
}) {
  // On utilise du HTML/CSS plutôt que SVG pour le horizontal : plus simple
  // pour gérer label + valeur alignés et liens éventuels. Chaque ligne
  // contient une grille label | barre | valeur.
  const labelColW = 140;
  const valueColW = showValues ? 70 : 0;
  return (
    <div className={className} style={{ width }}>
      <div className="flex flex-col">
        {data.map((d, i) => {
          const total = d.values.reduce((s, v) => s + v, 0);
          if (mode === "stacked") {
            const widthPct = (total / maxValue) * 100;
            return (
              <div
                key={i}
                className="flex items-center gap-3 py-1"
                style={{ minHeight: lineHeight }}
              >
                <div
                  className="shrink-0 truncate text-xs text-muted-foreground"
                  style={{ width: labelColW }}
                  title={d.label}
                >
                  {d.label}
                </div>
                <div className="relative flex-1 overflow-hidden rounded-sm bg-surface-2">
                  <div className="flex h-4" style={{ width: `${widthPct}%` }}>
                    {d.values.map((v, k) => {
                      const pct = total > 0 ? (v / total) * 100 : 0;
                      return (
                        <div
                          key={k}
                          style={{ width: `${pct}%`, background: series[k]?.color }}
                          title={`${series[k]?.name ?? ""} : ${formatValue(v)}`}
                        />
                      );
                    })}
                  </div>
                </div>
                {showValues && (
                  <div
                    className="shrink-0 text-right text-xs tabular-nums"
                    style={{ width: valueColW }}
                  >
                    {formatValue(total)}
                  </div>
                )}
              </div>
            );
          }
          // Simple / grouped : N barres empilées verticalement dans la ligne.
          return (
            <div
              key={i}
              className="flex items-center gap-3 py-1"
              style={{ minHeight: lineHeight }}
            >
              <div
                className="shrink-0 truncate text-xs text-muted-foreground"
                style={{ width: labelColW }}
                title={d.label}
              >
                {d.label}
              </div>
              <div className="flex-1 space-y-0.5">
                {d.values.map((v, k) => {
                  const pct = (v / maxValue) * 100;
                  return (
                    <div key={k} className="relative h-3 overflow-hidden rounded-sm bg-surface-2">
                      <div
                        className="h-full"
                        style={{
                          width: `${pct}%`,
                          background: series[k]?.color,
                        }}
                        title={`${series[k]?.name ?? ""} : ${formatValue(v)}`}
                      />
                    </div>
                  );
                })}
              </div>
              {showValues && (
                <div
                  className="shrink-0 text-right text-xs tabular-nums"
                  style={{ width: valueColW }}
                >
                  {d.values.length === 1
                    ? formatValue(d.values[0])
                    : formatValue(total)}
                </div>
              )}
            </div>
          );
        })}
      </div>
      {legend && series.length > 1 && <Legend series={series} />}
    </div>
  );
}

function Legend({ series }: { series: Array<Series & { color: string }> }) {
  return (
    <ul className="mt-3 flex flex-wrap gap-x-4 gap-y-1 text-[11px] text-muted-foreground">
      {series.map((s, i) => (
        <li key={i} className="flex items-center gap-1.5">
          <span
            className="inline-block size-2.5 rounded-sm"
            style={{ background: s.color }}
            aria-hidden="true"
          />
          {s.name}
        </li>
      ))}
    </ul>
  );
}
