type Bucket = { key: string; count: number; sum?: number };

export type LinePoint = { x: string; values: Record<string, number> };

const COLORS = ["#1d4f91", "#7c3aed", "#c2410c", "#0f766e", "#b42318", "#854d0e"];

export function KpiCard({ title, value }: { title: string; value: string | number }) {
  return (
    <div className="kpi">
      <div className="kpi-title">{title}</div>
      <div className="kpi-value">{value}</div>
    </div>
  );
}

export function BarChart({ title, buckets }: { title: string; buckets: Bucket[] }) {
  const max = Math.max(1, ...buckets.map((b) => b.count));
  return (
    <div className="chart-card">
      <h4>{title}</h4>
      <div className="bars">
        {buckets.map((b, i) => (
          <div className="bar-row" key={b.key}>
            <span className="bar-label">{b.key}</span>
            <div className="bar-track">
              <div
                className="bar-fill"
                style={{ width: `${(b.count / max) * 100}%`, background: COLORS[i % COLORS.length] }}
              />
            </div>
            <span className="bar-num">{b.count}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

export function PieChart({ title, buckets }: { title: string; buckets: Bucket[] }) {
  const total = buckets.reduce((s, b) => s + b.count, 0) || 1;
  let acc = 0;
  const stops = buckets.map((b, i) => {
    const start = (acc / total) * 100;
    acc += b.count;
    const end = (acc / total) * 100;
    return `${COLORS[i % COLORS.length]} ${start}% ${end}%`;
  });
  return (
    <div className="chart-card">
      <h4>{title}</h4>
      <div className="pie-wrap">
        <div className="pie" style={{ background: `conic-gradient(${stops.join(",")})` }} />
        <ul className="pie-legend">
          {buckets.map((b, i) => (
            <li key={b.key}>
              <i style={{ background: COLORS[i % COLORS.length] }} />
              {b.key} · {b.count}
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}

/** 折线：X 为类目/序号/里程，Y 为多系列数值 */
export function LineChart({
  title,
  points,
  series,
  yUnit = "",
}: {
  title: string;
  points: LinePoint[];
  series: { key: string; label: string }[];
  yUnit?: string;
}) {
  if (!points.length || !series.length) {
    return (
      <div className="chart-card line-chart">
        {title ? <h4>{title}</h4> : null}
        <div className="empty">暂无曲线数据</div>
      </div>
    );
  }

  const nums = points.flatMap((p) => series.map((s) => p.values[s.key]).filter((n) => Number.isFinite(n))) as number[];
  // 用分位裁掉极端尖刺，避免一根异常值把曲线压成一条线
  const sorted = [...nums].sort((a, b) => a - b);
  const q = (p: number) => {
    if (!sorted.length) return 0;
    const i = Math.min(sorted.length - 1, Math.max(0, Math.floor((sorted.length - 1) * p)));
    return sorted[i];
  };
  let minY = sorted.length ? Math.min(0, q(0.05)) : 0;
  let maxY = sorted.length ? Math.max(1, q(0.95)) : 1;
  if (maxY - minY < 1) {
    minY = Math.min(0, ...nums, -1);
    maxY = Math.max(1, ...nums, 1);
  }
  const pad = (maxY - minY) * 0.12 || 1;
  const y0 = minY - pad;
  const y1 = maxY + pad;
  const W = 920;
  const H = 280;
  const L = 48;
  const R = 16;
  const T = 20;
  const B = 36;
  const plotW = W - L - R;
  const plotH = H - T - B;

  const xAt = (i: number) => L + (points.length <= 1 ? plotW / 2 : (i / (points.length - 1)) * plotW);
  const yAt = (v: number) => T + ((y1 - v) / (y1 - y0)) * plotH;

  const paths = series.map((s, si) => {
    const d = points
      .map((p, i) => {
        const v = p.values[s.key];
        if (!Number.isFinite(v)) return null;
        const cmd = i === 0 || !Number.isFinite(points[i - 1]?.values[s.key]) ? "M" : "L";
        return `${cmd}${xAt(i).toFixed(1)},${yAt(v).toFixed(1)}`;
      })
      .filter(Boolean)
      .join(" ");
    return { ...s, d, color: COLORS[si % COLORS.length] };
  });

  const ticks = 5;
  const yTicks = Array.from({ length: ticks }, (_, i) => y0 + ((y1 - y0) * i) / (ticks - 1));

  return (
    <div className="chart-card line-chart">
      <div className="line-chart-head">
        {title ? <h4>{title}</h4> : null}
        <ul className="line-legend">
          {paths.map((p) => (
            <li key={p.key}>
              <i style={{ background: p.color }} />
              {p.label}
            </li>
          ))}
        </ul>
      </div>
      <div className="line-chart-scroll">
        <svg
          viewBox={`0 0 ${W} ${H}`}
          width="100%"
          height={H}
          preserveAspectRatio="none"
          role="img"
        >
          {yTicks.map((t) => (
            <g key={t}>
              <line x1={L} x2={W - R} y1={yAt(t)} y2={yAt(t)} className="line-grid" />
              <text x={L - 6} y={yAt(t) + 4} className="line-axis" textAnchor="end">
                {t.toFixed(0)}
              </text>
            </g>
          ))}
          <text x={8} y={14} className="line-axis">
            {yUnit}
          </text>
          {paths.map((p) => (
            <path key={p.key} d={p.d} fill="none" stroke={p.color} strokeWidth={2.2} />
          ))}
          {points.map((p, i) => (
            <text
              key={`${p.x}-${i}`}
              x={xAt(i)}
              y={H - 10}
              className="line-axis"
              textAnchor="middle"
            >
              {i % Math.ceil(points.length / 8) === 0 ? p.x : ""}
            </text>
          ))}
        </svg>
      </div>
    </div>
  );
}

/** 着色短棒 + 可选参考曲线（screenshot_faithful 通用图元） */
export function SectionMarkChart({
  points,
  yUnit = "",
  yAxisLabel = "",
  designColor = "#e8590c",
  invertY = false,
}: {
  points: { x: string; value: number; design?: number; color?: string }[];
  yUnit?: string;
  yAxisLabel?: string;
  designColor?: string;
  /** 为 true 时纵轴方向与常规相反（上小下大），由 meta.ui.invert_y 控制 */
  invertY?: boolean;
}) {
  if (!points.length) {
    return (
      <div className="chart-card line-chart">
        <div className="empty">暂无曲线数据</div>
      </div>
    );
  }
  const vals = points.map((p) => p.value).filter((n) => Number.isFinite(n));
  const designs = points.map((p) => p.design).filter((n): n is number => Number.isFinite(n as number));
  const all = [...vals, ...designs];
  let minY = all.length ? Math.min(...all) : 0;
  let maxY = all.length ? Math.max(...all) : 1;
  if (maxY - minY < 1e-6) {
    minY -= 1;
    maxY += 1;
  }
  const pad = (maxY - minY) * 0.08 || 1;
  minY -= pad;
  maxY += pad;
  const W = Math.max(920, points.length * 22);
  const H = 260;
  const L = 52;
  const R = 12;
  const T = 16;
  const B = 34;
  const plotW = W - L - R;
  const plotH = H - T - B;
  const xAt = (i: number) => L + (points.length <= 1 ? plotW / 2 : (i / (points.length - 1)) * plotW);
  const yAt = (v: number) => {
    if (invertY) {
      return T + ((v - minY) / (maxY - minY)) * plotH;
    }
    return T + ((maxY - v) / (maxY - minY)) * plotH;
  };
  const tickN = 6;
  const yTicks = Array.from({ length: tickN }, (_, i) => minY + ((maxY - minY) * i) / (tickN - 1));
  const unitSuffix = yUnit ? String(yUnit) : "";
  const designPath = points
    .map((p, i) => {
      const d = p.design;
      if (!Number.isFinite(d as number)) return null;
      const cmd = i === 0 || !Number.isFinite(points[i - 1]?.design as number) ? "M" : "L";
      return `${cmd}${xAt(i).toFixed(1)},${yAt(d as number).toFixed(1)}`;
    })
    .filter(Boolean)
    .join(" ");

  return (
    <div className="chart-card line-chart section-mark-chart">
      <div className="line-chart-scroll">
        <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} preserveAspectRatio="none" role="img">
          {yTicks.map((t) => (
            <g key={t}>
              <line x1={L} x2={W - R} y1={yAt(t)} y2={yAt(t)} className="line-grid" />
              <text x={L - 6} y={yAt(t) + 4} className="line-axis" textAnchor="end">
                {Number.isInteger(t) ? String(t) : t.toFixed(1)}
                {unitSuffix}
              </text>
            </g>
          ))}
          {yAxisLabel ? (
            <text x={6} y={14} className="line-axis">
              {yAxisLabel}
            </text>
          ) : null}
          {designPath ? <path d={designPath} fill="none" stroke={designColor} strokeWidth={2} /> : null}
          {points.map((p, i) => {
            const v = p.value;
            if (!Number.isFinite(v)) return null;
            const x = xAt(i);
            const y = yAt(v);
            const y0 = yAt(0);
            const top = Math.min(y, y0);
            const h = Math.max(3, Math.abs(y - y0));
            return (
              <rect
                key={`${p.x}-${i}`}
                x={x - 3}
                y={top}
                width={6}
                height={h}
                fill={p.color || "#214080"}
                opacity={0.9}
              />
            );
          })}
          {points.map((p, i) => (
            <text key={`lb-${i}`} x={xAt(i)} y={H - 8} className="line-axis" textAnchor="middle">
              {i % Math.ceil(points.length / 8) === 0 ? p.x : ""}
            </text>
          ))}
        </svg>
      </div>
    </div>
  );
}

/** 状态条：单值格，或双段竖条（上/下分段，由 widget.variant=stacked* 驱动） */
export function StatusStrip({
  title,
  items,
  variant = "cells",
}: {
  title: string;
  items: {
    label: string;
    value: number;
    secondary?: number;
    tone?: "ok" | "warn" | "muted";
    stop?: boolean;
  }[];
  variant?: "cells" | "stacked";
}) {
  if (variant === "stacked") {
    return (
      <div className="chart-card status-strip status-strip-stacked">
        {title ? <h4>{title}</h4> : null}
        <div className="status-strip-row stacked-row">
          {items.map((it, i) => {
            if (it.stop) {
              return (
                <div key={`${it.label}-${i}`} className="status-stack stop" title={it.label}>
                  <span className="stack-stop">停</span>
                </div>
              );
            }
            const top = Math.max(0, Number(it.value) || 0);
            const bottom = Math.max(0, Number(it.secondary) || 0);
            const sum = top + bottom || 1;
            // 几乎全灰：下段过小则整条灰显示上段天数
            if (bottom <= 0 && top > 0) {
              return (
                <div key={`${it.label}-${i}`} className="status-stack all-grey" title={it.label}>
                  <span className="stack-solo">{top}</span>
                </div>
              );
            }
            if (top <= 0 && bottom > 0) {
              return (
                <div key={`${it.label}-${i}`} className="status-stack all-green" title={it.label}>
                  <span className="stack-solo">{bottom}</span>
                </div>
              );
            }
            const topPct = (top / sum) * 100;
            const botPct = (bottom / sum) * 100;
            return (
              <div key={`${it.label}-${i}`} className="status-stack" title={it.label}>
                <div className="stack-top" style={{ flex: `${Math.max(topPct, 8)} 1 0` }}>
                  <span>{top}</span>
                </div>
                <div className="stack-bot" style={{ flex: `${Math.max(botPct, 8)} 1 0` }}>
                  <span>{bottom}</span>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    );
  }

  return (
    <div className="chart-card status-strip">
      {title ? <h4>{title}</h4> : null}
      <div className="status-strip-row">
        {items.map((it, i) => (
          <div key={`${it.label}-${i}`} className={`status-cell tone-${it.tone || "ok"}`} title={it.label}>
            <span className="status-top">{it.label}</span>
            <span className="status-val">{it.value}</span>
          </div>
        ))}
      </div>
    </div>
  );
}
