import type { AriaAttributes, ReactNode } from "react";
import { cn } from "./cn";
import { Icon, type IconName } from "./Icon";

export type Tone = "red" | "amber" | "green" | "blue" | "indigo" | "purple" | "pink" | "grey";

// Literal strings so Tailwind finds every class.
const tint: Record<Tone, { fill: string; icon: string; dot: string }> = {
  red: { fill: "bg-red-fill text-red-text", icon: "text-red-icon", dot: "bg-red-icon" },
  amber: { fill: "bg-amber-fill text-amber-text", icon: "text-amber-icon", dot: "bg-amber-icon" },
  green: { fill: "bg-green-fill text-green-text", icon: "text-green-icon", dot: "bg-green-icon" },
  blue: { fill: "bg-blue-fill text-blue-text", icon: "text-blue-icon", dot: "bg-blue-icon" },
  indigo: { fill: "bg-indigo-fill text-indigo-text", icon: "text-indigo-icon", dot: "bg-indigo-icon" },
  purple: { fill: "bg-purple-fill text-purple-text", icon: "text-purple-icon", dot: "bg-purple-icon" },
  pink: { fill: "bg-pink-fill text-pink-text", icon: "text-pink-icon", dot: "bg-pink-icon" },
  grey: { fill: "bg-grey-fill text-grey-text", icon: "text-grey-icon", dot: "bg-grey-icon" },
};
export const toneText = (t: Tone) => tint[t].icon;
export const toneDot = (t: Tone) => tint[t].dot;

/** A state: tinted, a filled icon and always its words, so colour is never the only signal. */
export function StatusPill({
  tone,
  icon,
  children,
  outline = false,
  size = "md",
  title,
  className,
}: {
  tone: Tone;
  icon?: IconName;
  children: ReactNode;
  outline?: boolean;
  size?: "sm" | "md";
  title?: string;
  className?: string;
}) {
  return (
    <span
      title={title}
      className={cn(
        "inline-flex items-center gap-[5px] rounded-full font-medium whitespace-nowrap",
        size === "md" ? "h-[26px] pr-2.5 pl-1.5 text-[13px]" : "h-[22px] pr-2 pl-1 text-[12px]",
        !icon && (size === "md" ? "pl-2.5" : "pl-2"),
        outline ? cn("bg-page shadow-[inset_0_0_0_1px_currentColor]", tint[tone].fill.split(" ")[1]) : tint[tone].fill,
        className,
      )}
    >
      {icon && <Icon name={icon} size={size === "md" ? 16 : 14} className={tint[tone].icon} />}
      {children}
    </span>
  );
}

/** Solid badge, kept for who someone is (Verified, Licence lapsed), never for a state. */
export function SolidBadge({ tone, icon, children }: { tone: "red" | "green" | "grey" | "ink"; icon?: IconName; children: ReactNode }) {
  const bg = { red: "bg-red-icon", green: "bg-action", grey: "bg-grey-icon", ink: "bg-ink" }[tone];
  return (
    <span className={cn("inline-flex h-[22px] items-center gap-1 rounded-full pr-[9px] pl-[5px] text-[12px] font-semibold text-white", !icon && "pl-[9px]", bg)}>
      {icon && <Icon name={icon} size={14} />}
      {children}
    </span>
  );
}

/** Outlined DM Mono tag for codes, units, sources and filters. */
export function Tag({ children, lead, trail, count, className }: { children: ReactNode; lead?: IconName; trail?: IconName; count?: number; className?: string }) {
  return (
    <span
      className={cn(
        "inline-flex h-6 items-center gap-[5px] rounded-md px-2 font-mono text-[12px] font-medium whitespace-nowrap text-body shadow-[inset_0_0_0_1px_var(--color-line)]",
        lead && "pl-1.5",
        (trail || count !== undefined) && "pr-1",
        className,
      )}
    >
      {lead && <Icon name={lead} size={14} className="text-muted" />}
      {children}
      {trail && <Icon name={trail} size={14} className="text-subtle" />}
      {count !== undefined && <span className="ml-0.5 rounded bg-quiet px-1.5 py-px text-[11px] text-muted">{count}</span>}
    </span>
  );
}

/** Small count next to a section title or a nav item. */
export function Count({ children, tone = "grey", className, ...aria }: { children: ReactNode; tone?: "grey" | "red" | "ink"; className?: string } & AriaAttributes) {
  const c = { grey: "bg-quiet text-muted", red: "bg-red-icon text-white", ink: "bg-grey-icon text-white" }[tone];
  return (
    <span className={cn("inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full px-1.5 font-mono text-[11px] leading-none font-medium", c, className)} {...aria}>
      {children}
    </span>
  );
}

/** A small dot of colour. Decorative unless it is given a role and a label. */
export function Dot({ tone, className, role, ...aria }: { tone: Tone; className?: string; role?: "img" } & AriaAttributes) {
  return <span role={role} aria-hidden={role ? undefined : true} className={cn("inline-block size-1.5 shrink-0 rounded-full", tint[tone].dot, className)} {...aria} />;
}
