import { cn } from "@/lib/cn";

export type AdminChartDatum = {
  key: string;
  label: string;
  value: number;
  /** Optional pre-formatted display value (e.g. currency). */
  displayValue?: string;
  color?: string;
};

const DEFAULT_COLORS = [
  "var(--color-primary)",
  "var(--color-accent)",
  "#059669",
  "#D97706",
  "#DC2626",
  "rgba(51, 65, 85, 0.45)",
];

function percentOf(value: number, total: number): number {
  if (total <= 0) {
    return 0;
  }
  return (value / total) * 100;
}

function formatPercent(value: number, total: number): string {
  if (total <= 0) {
    return "0%";
  }
  const pct = percentOf(value, total);
  if (pct > 0 && pct < 1) {
    return "<1%";
  }
  return `${Math.round(pct)}%`;
}

function hasPositiveValues(data: AdminChartDatum[]): boolean {
  return data.some((item) => item.value > 0);
}

/** Horizontal distribution bars — campaign status, readiness, etc. */
export function AdminHorizontalBarChart({
  data,
  title,
  className,
  ariaLabel,
  emptyMessage,
}: {
  data: AdminChartDatum[];
  title?: string;
  className?: string;
  ariaLabel: string;
  emptyMessage?: string;
}) {
  const total = data.reduce((sum, item) => sum + Math.max(0, item.value), 0);
  const max = Math.max(...data.map((item) => item.value), 0);
  const isEmpty = !hasPositiveValues(data);

  return (
    <div className={cn("space-y-3", className)} role="img" aria-label={ariaLabel}>
      {title ? (
        <p className="text-[0.8125rem] font-semibold text-primary">{title}</p>
      ) : null}

      {isEmpty && emptyMessage ? (
        <p className="rounded-[10px] border border-dashed border-line/80 bg-[#FAFBFC] px-3.5 py-4 text-[0.8125rem] leading-relaxed text-ink-60">
          {emptyMessage}
        </p>
      ) : (
        <ul className="space-y-2.5">
          {data.map((item, index) => {
            const widthPct = max > 0 ? (item.value / max) * 100 : 0;
            const color = item.color ?? DEFAULT_COLORS[index % DEFAULT_COLORS.length];
            const isZero = item.value <= 0;

            return (
              <li key={item.key} className="space-y-1.5">
                <div className="flex items-baseline justify-between gap-3">
                  <span
                    className={cn(
                      "min-w-0 truncate text-[0.8125rem] font-medium",
                      isZero ? "text-ink-40" : "text-primary",
                    )}
                  >
                    {item.label}
                  </span>
                  <span className="shrink-0 text-[0.8125rem] tabular-nums text-ink-60">
                    <span className={cn("font-semibold", isZero ? "text-ink-40" : "text-primary")}>
                      {item.displayValue ?? item.value}
                    </span>
                    <span className="ml-2 text-ink-40">{formatPercent(item.value, total)}</span>
                  </span>
                </div>
                <div className="h-2.5 overflow-hidden rounded-full bg-slate-100" aria-hidden="true">
                  <div
                    className="h-full rounded-full transition-[width] duration-300 motion-reduce:transition-none"
                    style={{
                      width: `${widthPct}%`,
                      backgroundColor: color,
                      minWidth: item.value > 0 ? "0.25rem" : 0,
                      opacity: isZero ? 0 : 1,
                    }}
                  />
                </div>
              </li>
            );
          })}
        </ul>
      )}

      <p className="sr-only">
        {data.map((item) => `${item.label}: ${item.displayValue ?? item.value}`).join(". ")}
      </p>
    </div>
  );
}

/** Compact donut for categorical totals (e.g. campaign status). */
export function AdminDonutChart({
  data,
  centerLabel,
  centerValue,
  className,
  ariaLabel,
}: {
  data: AdminChartDatum[];
  centerLabel: string;
  centerValue: string | number;
  className?: string;
  ariaLabel: string;
}) {
  const total = data.reduce((sum, item) => sum + Math.max(0, item.value), 0);
  const size = 152;
  const stroke = 16;
  const radius = (size - stroke) / 2;
  const circumference = 2 * Math.PI * radius;

  let offset = 0;
  const segments =
    total <= 0
      ? []
      : data
          .filter((item) => item.value > 0)
          .map((item, index) => {
            const length = (item.value / total) * circumference;
            const segment = {
              ...item,
              color: item.color ?? DEFAULT_COLORS[index % DEFAULT_COLORS.length],
              dasharray: `${length} ${circumference - length}`,
              dashoffset: -offset,
            };
            offset += length;
            return segment;
          });

  return (
    <div
      className={cn(
        "flex flex-col items-center gap-5 lg:flex-row lg:items-center lg:gap-6",
        className,
      )}
    >
      <div className="relative shrink-0" role="img" aria-label={ariaLabel}>
        <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} aria-hidden="true">
          <circle
            cx={size / 2}
            cy={size / 2}
            r={radius}
            fill="none"
            stroke="rgba(23, 37, 84, 0.08)"
            strokeWidth={stroke}
          />
          {segments.length === 0 ? null : (
            <g transform={`rotate(-90 ${size / 2} ${size / 2})`}>
              {segments.map((segment) => (
                <circle
                  key={segment.key}
                  cx={size / 2}
                  cy={size / 2}
                  r={radius}
                  fill="none"
                  stroke={segment.color}
                  strokeWidth={stroke}
                  strokeDasharray={segment.dasharray}
                  strokeDashoffset={segment.dashoffset}
                  strokeLinecap="butt"
                />
              ))}
            </g>
          )}
        </svg>
        <div className="pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center">
          <p className="text-[1.5rem] font-semibold tabular-nums tracking-[-0.03em] text-primary">
            {centerValue}
          </p>
          <p className="mt-0.5 text-[0.75rem] font-medium text-ink-40">{centerLabel}</p>
        </div>
      </div>
      <ul className="w-full min-w-0 divide-y divide-line/70">
        {data.map((item, index) => {
          const isZero = item.value <= 0;
          return (
            <li
              key={item.key}
              className="flex items-center justify-between gap-3 py-2 first:pt-0 last:pb-0 text-[0.8125rem]"
            >
              <span className="flex min-w-0 items-center gap-2.5">
                <span
                  className="size-2.5 shrink-0 rounded-full ring-1 ring-black/5"
                  style={{
                    backgroundColor: item.color ?? DEFAULT_COLORS[index % DEFAULT_COLORS.length],
                    opacity: isZero ? 0.45 : 1,
                  }}
                  aria-hidden="true"
                />
                <span
                  className={cn(
                    "truncate font-medium",
                    isZero ? "text-ink-40" : "text-primary",
                  )}
                >
                  {item.label}
                </span>
              </span>
              <span className="shrink-0 tabular-nums">
                <span className={cn("font-semibold", isZero ? "text-ink-40" : "text-primary")}>
                  {item.displayValue ?? item.value}
                </span>
                <span className="ml-2 inline-block min-w-[2.25rem] text-right text-ink-40">
                  {formatPercent(item.value, total)}
                </span>
              </span>
            </li>
          );
        })}
      </ul>
    </div>
  );
}

/** Aggregate comparison bars (not a time series). */
export function AdminComparisonBarChart({
  data,
  className,
  ariaLabel,
  emptyTitle = "No successful payments yet.",
  emptyDescription = "Financial visualizations will populate as transactions occur.",
}: {
  data: AdminChartDatum[];
  className?: string;
  ariaLabel: string;
  emptyTitle?: string;
  emptyDescription?: string;
}) {
  const max = Math.max(...data.map((item) => item.value), 0);
  const chartHeight = 128;
  const isEmpty = !hasPositiveValues(data);

  if (isEmpty) {
    return (
      <div
        className={cn(
          "flex min-h-[11rem] flex-col items-start justify-center rounded-[10px] border border-dashed border-line/80 bg-[#FAFBFC] px-4 py-5",
          className,
        )}
        role="status"
        aria-label={ariaLabel}
      >
        <p className="text-[0.875rem] font-semibold text-primary">{emptyTitle}</p>
        <p className="mt-1.5 max-w-[40ch] text-[0.8125rem] leading-relaxed text-ink-60">
          {emptyDescription}
        </p>
        <ul className="mt-4 w-full space-y-1.5 border-t border-line pt-3">
          {data.map((item) => (
            <li
              key={item.key}
              className="flex items-center justify-between gap-3 text-[0.8125rem]"
            >
              <span className="text-ink-60">{item.label}</span>
              <span className="tabular-nums text-ink-40">{item.displayValue ?? item.value}</span>
            </li>
          ))}
        </ul>
      </div>
    );
  }

  return (
    <div className={cn("min-w-0 space-y-3", className)} role="img" aria-label={ariaLabel}>
      <div className="flex h-[128px] items-end gap-2 sm:gap-3">
        {data.map((item, index) => {
          const height =
            max > 0 ? Math.max((item.value / max) * chartHeight, item.value > 0 ? 6 : 0) : 0;
          const color = item.color ?? DEFAULT_COLORS[index % DEFAULT_COLORS.length];
          const display = item.displayValue ?? String(item.value);

          return (
            <div key={item.key} className="flex min-w-0 flex-1 flex-col items-center gap-1.5">
              <p
                className={cn(
                  "max-w-full truncate text-center text-[0.6875rem] font-semibold tabular-nums sm:text-[0.75rem]",
                  item.value > 0 ? "text-primary" : "text-ink-40",
                )}
                title={display}
              >
                {item.value > 0 ? display : "—"}
              </p>
              <div className="flex w-full flex-1 items-end justify-center">
                {item.value > 0 ? (
                  <div
                    className="w-[70%] max-w-[3.75rem] rounded-t-[6px] sm:w-[76%] sm:max-w-[4.5rem]"
                    style={{ height, backgroundColor: color }}
                    aria-hidden="true"
                  />
                ) : (
                  <div
                    className="w-[70%] max-w-[3.75rem] border-t border-dashed border-line sm:w-[76%] sm:max-w-[4.5rem]"
                    aria-hidden="true"
                  />
                )}
              </div>
            </div>
          );
        })}
      </div>
      <div className="flex gap-2 sm:gap-3">
        {data.map((item) => (
          <p
            key={item.key}
            className="min-w-0 flex-1 text-center text-[0.6875rem] leading-snug text-ink-60 sm:text-[0.75rem]"
          >
            {item.label}
          </p>
        ))}
      </div>
      <p className="sr-only">
        {data.map((item) => `${item.label}: ${item.displayValue ?? item.value}`).join(". ")}
      </p>
    </div>
  );
}

export function adminChartPercent(value: number, total: number): string {
  return formatPercent(value, total);
}
