/* =============================================================
   charts.jsx — light, dependency-free SVG charts
   ============================================================= */
function BarChart({ data, max, fmt = (v) => v, accent }) {
  if (!data || !data.length) return <Empty title="No data" />;
  const m = max ?? Math.max(...data.map((d) => d.value), 1);
  return (
    <div className="bar-chart">
      {data.map((d, i) => (
        <div className="bar-row" key={d.label + i}>
          <div className="lbl ellipsis" title={d.label}>{d.label}</div>
          <div className="bar"><span style={{ width: ((d.value / m) * 100).toFixed(1) + "%", background: d.color || accent || "var(--accent)" }} /></div>
          <div className="num">{fmt(d.value)}</div>
        </div>
      ))}
    </div>
  );
}

function StackedBar({ segments, fmt = (v) => v, total }) {
  const sum = (total ?? segments.reduce((a, b) => a + b.value, 0)) || 1;
  return (
    <>
      <div className="stack-bar">
        {segments.map((s, i) => (
          <span key={i} title={`${s.label}: ${s.value}`}
                style={{ width: ((s.value / sum) * 100).toFixed(2) + "%", background: s.color }} />
        ))}
      </div>
      <div style={{display:"flex", flexWrap:"wrap", gap: "8px 14px", marginTop: 10, fontSize: 12}}>
        {segments.map((s, i) => (
          <div key={i} style={{display:"flex", alignItems:"center", gap: 6, color: "var(--ink-700)"}}>
            <span style={{width: 8, height: 8, borderRadius: 2, background: s.color}} />
            <span>{s.label}</span>
            <span className="mono" style={{color: "var(--ink-500)"}}>{fmt(s.value)}</span>
          </div>
        ))}
      </div>
    </>
  );
}

function Donut({ value, total, label = "Complete", size = 140, color = "var(--accent)" }) {
  const pct = total > 0 ? value / total : 0;
  const r = size / 2 - 12;
  const c = 2 * Math.PI * r;
  const offset = c * (1 - pct);
  return (
    <div className="donut" style={{width: size, height: size, margin: "0 auto"}}>
      <svg width={size} height={size}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="var(--bg-sunken)" strokeWidth="10"/>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={color} strokeWidth="10" strokeLinecap="round"
                strokeDasharray={c} strokeDashoffset={offset}
                transform={`rotate(-90 ${size/2} ${size/2})`}
                style={{transition: "stroke-dashoffset .6s cubic-bezier(.2,.7,.2,1)"}}/>
      </svg>
      <div className="center">
        <div>
          <div className="v">{Math.round(pct * 100)}%</div>
          <div className="l">{label}</div>
        </div>
      </div>
    </div>
  );
}

function Funnel({ steps, fmt = (v) => v }) {
  const max = Math.max(...steps.map((s) => s.value), 1);
  return (
    <div className="funnel">
      {steps.map((s, i) => (
        <div className="funnel-step" key={s.label + i}>
          <div className="fbar" style={{ width: ((s.value / max) * 100).toFixed(1) + "%" }} />
          <div className="ftext">{s.label}</div>
          <div className="fnum">{fmt(s.value)}</div>
        </div>
      ))}
    </div>
  );
}

// Generic horizontal histogram of "days slipped" buckets
function Histogram({ data, color = "var(--accent)" }) {
  if (!data || !data.length) return <Empty title="No data" />;
  const max = Math.max(...data.map((d) => d.value), 1);
  const h = 130;
  const bw = 28;
  const gap = 6;
  const w = data.length * (bw + gap);
  return (
    <svg width="100%" height={h + 30} viewBox={`0 0 ${w} ${h + 30}`} preserveAspectRatio="xMinYMin meet">
      {data.map((d, i) => {
        const bh = (d.value / max) * (h - 10);
        const x = i * (bw + gap);
        return (
          <g key={i}>
            <rect x={x} y={h - bh} width={bw} height={bh} rx={3} fill={d.color || color}/>
            <text x={x + bw / 2} y={h - bh - 4} fontSize={10} textAnchor="middle" fill="var(--ink-500)" fontFamily="var(--font-mono)">{d.value || ""}</text>
            <text x={x + bw / 2} y={h + 14} fontSize={10} textAnchor="middle" fill="var(--ink-500)">{d.label}</text>
          </g>
        );
      })}
    </svg>
  );
}

/* ---------- MetricRing: a compact KPI with a donut ring on the right ----------
   Use for overview cards where users want to see "X of Y done" at a glance. */
function MetricRing({ label, value, total, hint, color = "var(--accent)", accent, size = 72, valueLabel, format = (v) => v.toLocaleString() }) {
  const pct = total > 0 ? Math.min(1, value / total) : 0;
  const r = size / 2 - 7;
  const c = 2 * Math.PI * r;
  const offset = c * (1 - pct);
  const pctStr = total > 0 ? Math.round(pct * 100) + "%" : "—";
  return (
    <div className={"kpi metric-ring" + (accent ? " accent" : "")}>
      <div style={{display:"flex", alignItems:"flex-start", gap: 14, width: "100%"}}>
        <div style={{flex: 1, minWidth: 0}}>
          <div className="label">{label}</div>
          <div className="value">{valueLabel ?? format(value)}</div>
          {total !== undefined && total !== null && (
            <div className="delta">
              <span>of {format(total)} total</span>
            </div>
          )}
          {hint && <div className="delta"><span>{hint}</span></div>}
        </div>
        <div style={{position: "relative", width: size, height: size, flexShrink: 0}}>
          <svg width={size} height={size}>
            <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="var(--bg-sunken)" strokeWidth="6"/>
            <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={color} strokeWidth="6" strokeLinecap="round"
                    strokeDasharray={c} strokeDashoffset={offset}
                    transform={`rotate(-90 ${size/2} ${size/2})`}
                    style={{transition: "stroke-dashoffset .6s cubic-bezier(.2,.7,.2,1)"}}/>
          </svg>
          <div style={{position:"absolute", inset: 0, display:"grid", placeItems:"center"}}>
            <span style={{fontFamily:"var(--font-mono)", fontSize: 12, fontWeight: 600, color: "var(--ink-900)"}}>{pctStr}</span>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ---------- ProgressBarKPI: a KPI with a horizontal achieved/total bar ----------
   Reads "value out of total" in a single sweep, mirrors the design language of
   .progress + .kpi while staying compact. */
function ProgressBarKPI({ label, value, total, hint, color = "var(--accent)", accent, format = (v) => v.toLocaleString(), suffix }) {
  const pct = total > 0 ? Math.min(1, Math.max(0, value / total)) : 0;
  const pctStr = total > 0 ? Math.round(pct * 100) + "%" : "—";
  return (
    <div className={"kpi" + (accent ? " accent" : "")}>
      <div className="label">{label}</div>
      <div className="value" style={{display:"flex", alignItems:"baseline", gap: 6}}>
        <span>{format(value)}</span>
        {total !== undefined && total !== null && (
          <span style={{fontSize: 13, color: "var(--ink-500)", fontWeight: 400}}>/ {format(total)}</span>
        )}
        {suffix && <span style={{fontSize: 14, fontWeight: 500, color: "var(--ink-500)"}}>{suffix}</span>}
      </div>
      <div style={{marginTop: 10, marginBottom: 4}}>
        <div className="progress thin">
          <span style={{ width: (pct * 100) + "%", background: color }} />
        </div>
      </div>
      <div className="delta">
        <span style={{fontFamily: "var(--font-mono)", color: "var(--ink-700)", fontWeight: 600}}>{pctStr}</span>
        {hint && <span style={{color: "var(--ink-500)"}}>· {hint}</span>}
      </div>
    </div>
  );
}

/* ---------- MultiSegmentBar: stacked horizontal bar showing several states ---------- */
function MultiSegmentBar({ label, segments, total, hint, accent }) {
  const sum = total ?? segments.reduce((a, b) => a + b.value, 0);
  return (
    <div className={"kpi" + (accent ? " accent" : "")}>
      <div className="label">{label}</div>
      <div className="value" style={{fontSize: 24}}>{(sum || 0).toLocaleString()}</div>
      <div style={{marginTop: 8}}>
        <div className="stack-bar">
          {segments.map((s, i) => {
            const w = sum > 0 ? (s.value / sum) * 100 : 0;
            return <span key={i} title={`${s.label}: ${s.value}`} style={{ width: w.toFixed(2) + "%", background: s.color }} />;
          })}
        </div>
        <div style={{display:"flex", flexWrap:"wrap", gap: "6px 12px", marginTop: 8, fontSize: 11.5, color: "var(--ink-500)"}}>
          {segments.map((s, i) => (
            <div key={i} style={{display:"flex", alignItems:"center", gap: 4}}>
              <span style={{width: 7, height: 7, borderRadius: 2, background: s.color}} />
              <span>{s.label}</span>
              <span className="mono" style={{color: "var(--ink-700)", fontWeight: 600}}>{s.value}</span>
            </div>
          ))}
        </div>
      </div>
      {hint && <div className="delta" style={{marginTop: 6}}><span>{hint}</span></div>}
    </div>
  );
}

/* ---------- PieChart: simple SVG pie with coloured segments ---------- */
function PieChart({ segments, size = 150, stroke = "white", activeIndex = null, onActiveIndex }) {
  const real = segments
    .map((s, i) => ({ ...s, _idx: i }))
    .filter((s) => s && s.value > 0);
  const total = real.reduce((a, s) => a + s.value, 0);
  if (!total) {
    return (
      <div style={{
        width: size, height: size, borderRadius: "50%",
        border: "1px dashed var(--ink-300)", display: "grid", placeItems: "center",
        color: "var(--ink-400)", fontSize: 11,
      }}>no data</div>
    );
  }
  const cx = size / 2, cy = size / 2, r = size / 2 - 2;
  const innerR = r * 0.58;
  const active = real.find((s) => s._idx === activeIndex) || null;
  const centerLabel = active ? active.label : "Total";
  const centerValue = active ? active.value : total;
  const centerPct = active ? Math.round((active.value / total) * 100) : 100;

  const point = (radius, angle) => ({
    x: cx + radius * Math.cos(angle),
    y: cy + radius * Math.sin(angle),
  });
  const donutPath = (a0, a1) => {
    const p0 = point(r, a0), p1 = point(r, a1);
    const q0 = point(innerR, a0), q1 = point(innerR, a1);
    const large = a1 - a0 > Math.PI ? 1 : 0;
    return [
      `M ${p0.x} ${p0.y}`,
      `A ${r} ${r} 0 ${large} 1 ${p1.x} ${p1.y}`,
      `L ${q1.x} ${q1.y}`,
      `A ${innerR} ${innerR} 0 ${large} 0 ${q0.x} ${q0.y}`,
      "Z",
    ].join(" ");
  };
  // Single full slice is rendered as a circle (SVG arcs can't draw a full 360°).
  if (real.length === 1) {
    return (
      <div className="pie-viz" style={{ width: size, height: size }}>
        <svg width={size} height={size}>
          <circle
            className={"pie-slice" + (activeIndex === real[0]._idx ? " active" : "")}
            cx={cx}
            cy={cy}
            r={(r + innerR) / 2}
            fill="none"
            stroke={real[0].color}
            strokeWidth={r - innerR}
            onMouseEnter={() => onActiveIndex && onActiveIndex(real[0]._idx)}
            onMouseLeave={() => onActiveIndex && onActiveIndex(null)}
          />
        </svg>
        <div className="pie-center">
          <div className="pie-center-value">{real[0].value.toLocaleString()}</div>
          <div className="pie-center-label">{real[0].label}</div>
          <div className="pie-center-pct">100%</div>
        </div>
      </div>
    );
  }
  let a0 = -Math.PI / 2;
  return (
    <div className="pie-viz" style={{ width: size, height: size }}>
      <svg width={size} height={size}>
        <circle cx={cx} cy={cy} r={r} fill="var(--bg-sunken)" opacity=".45"/>
        {real.map((s, i) => {
          const sweep = (s.value / total) * 2 * Math.PI;
          const a1 = a0 + sweep;
          const mid = a0 + sweep / 2;
          const isActive = activeIndex === s._idx;
          const lift = isActive ? 4 : 0;
          const d = donutPath(a0, a1);
          const transform = lift ? `translate(${Math.cos(mid) * lift} ${Math.sin(mid) * lift})` : undefined;
          a0 = a1;
          return (
            <path
              key={i}
              className={"pie-slice" + (isActive ? " active" : "")}
              d={d}
              fill={s.color}
              stroke={stroke}
              strokeWidth="1.5"
              transform={transform}
              onMouseEnter={() => onActiveIndex && onActiveIndex(s._idx)}
              onMouseLeave={() => onActiveIndex && onActiveIndex(null)}
            >
              <title>{`${s.label}: ${s.value.toLocaleString()} (${Math.round((s.value / total) * 100)}%)`}</title>
            </path>
          );
        })}
      </svg>
      <div className="pie-center">
        <div className="pie-center-value">{centerValue.toLocaleString()}</div>
        <div className="pie-center-label">{centerLabel}</div>
        <div className="pie-center-pct">{centerPct}%</div>
      </div>
    </div>
  );
}

/* ---------- KPIPop: KPI card + hover popover with pie + legend ----------
   Hover anywhere on the card to reveal the popover; mouseleave hides it. */
function KPIPop({
  label, value, hint, accent, format = (v) => v.toLocaleString(),
  segments, popTitle, popHint, side = "bottom", className = "",
}) {
  const [activeSegment, setActiveSegment] = React.useState(null);
  const total = (segments || []).reduce((a, s) => a + (s.value || 0), 0);
  return (
    <div className={"kpi kpi-hover" + (accent ? " accent" : "") + (className ? " " + className : "")}>
      <div className="label">{label}</div>
      <div className="value">{typeof value === "number" ? format(value) : value}</div>
      {hint && <div className="delta"><span>{hint}</span></div>}
      <div className="kpi-hint-row">
        <span className="kpi-hint-dot"/> Hover for breakdown
      </div>
      {segments && segments.length > 0 && (
        <div className={"kpi-pop kpi-pop-" + side}>
          <div className="kpi-pop-h">
            <div className="kpi-pop-title">{popTitle || label}</div>
            {popHint && <div className="kpi-pop-hint">{popHint}</div>}
          </div>
          <div className="kpi-pop-body">
            <PieChart
              segments={segments}
              size={132}
              activeIndex={activeSegment}
              onActiveIndex={setActiveSegment}
            />
            <ul className="kpi-pop-legend">
              {segments.map((s, i) => {
                const pct = total > 0 ? Math.round((s.value / total) * 100) : 0;
                return (
                  <li
                    key={i}
                    className={activeSegment === i ? "active" : ""}
                    onMouseEnter={() => setActiveSegment(i)}
                    onMouseLeave={() => setActiveSegment(null)}
                  >
                    <span className="dot" style={{background: s.color}}/>
                    <span className="lbl">{s.label}</span>
                    <span className="num"><span className="mono">{(s.value || 0).toLocaleString()}</span> <span className="pct">{pct}%</span></span>
                  </li>
                );
              })}
            </ul>
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { BarChart, StackedBar, Donut, Funnel, Histogram, MetricRing, ProgressBarKPI, MultiSegmentBar, PieChart, KPIPop });
