import type { ReactNode } from "react";
import clsx from "clsx";

/**
 * Small, dependency-free UI kit.
 *
 * These are plain server-renderable pieces styled with Tailwind. Anything that
 * needs state lives in its own "use client" component instead.
 */

// -----------------------------------------------------------------------------
// Buttons and links
// -----------------------------------------------------------------------------

export const buttonStyles = {
  base: "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-50 whitespace-nowrap",
  size: {
    sm: "h-8 px-3 text-[13px]",
    md: "h-9 px-4",
    lg: "h-10 px-5",
    icon: "h-8 w-8",
  },
  variant: {
    primary: "bg-brand-600 text-white hover:bg-brand-700 shadow-sm",
    secondary: "bg-white text-ink-700 border border-ink-200 hover:bg-ink-50 shadow-sm",
    ghost: "text-ink-600 hover:bg-ink-100",
    danger: "bg-rose-600 text-white hover:bg-rose-700 shadow-sm",
    subtle: "bg-brand-50 text-brand-700 hover:bg-brand-100",
  },
} as const;

export function buttonClass(
  variant: keyof typeof buttonStyles.variant = "primary",
  size: keyof typeof buttonStyles.size = "md",
  extra?: string,
): string {
  return clsx(buttonStyles.base, buttonStyles.size[size], buttonStyles.variant[variant], extra);
}

// -----------------------------------------------------------------------------
// Surfaces
// -----------------------------------------------------------------------------

export function Card({
  children,
  className,
  as: Component = "section",
}: {
  children: ReactNode;
  className?: string;
  as?: "section" | "div" | "article";
}) {
  return (
    <Component className={clsx("rounded-xl border border-ink-200 bg-white shadow-sm", className)}>
      {children}
    </Component>
  );
}

export function CardHeader({
  title,
  description,
  actions,
  className,
}: {
  title: ReactNode;
  description?: ReactNode;
  actions?: ReactNode;
  className?: string;
}) {
  return (
    <div
      className={clsx(
        "flex flex-wrap items-start justify-between gap-3 border-b border-ink-200 px-5 py-4",
        className,
      )}
    >
      <div className="min-w-0">
        <h2 className="text-sm font-semibold text-ink-900">{title}</h2>
        {description ? <p className="mt-0.5 text-[13px] text-ink-500">{description}</p> : null}
      </div>
      {actions ? <div className="flex shrink-0 flex-wrap items-center gap-2">{actions}</div> : null}
    </div>
  );
}

export function PageHeader({
  title,
  description,
  actions,
  breadcrumb,
}: {
  title: ReactNode;
  description?: ReactNode;
  actions?: ReactNode;
  breadcrumb?: ReactNode;
}) {
  return (
    <header className="mb-6">
      {breadcrumb ? <div className="mb-2 text-[13px] text-ink-500">{breadcrumb}</div> : null}
      <div className="flex flex-wrap items-start justify-between gap-4">
        <div className="min-w-0">
          <h1 className="text-xl font-semibold tracking-tight text-ink-900">{title}</h1>
          {description ? <p className="mt-1 max-w-3xl text-sm text-ink-500">{description}</p> : null}
        </div>
        {actions ? <div className="flex flex-wrap items-center gap-2">{actions}</div> : null}
      </div>
    </header>
  );
}

// -----------------------------------------------------------------------------
// Stat cards
// -----------------------------------------------------------------------------

export function StatCard({
  label,
  value,
  hint,
  tone = "default",
  icon,
}: {
  label: string;
  value: ReactNode;
  hint?: ReactNode;
  tone?: "default" | "brand" | "teal" | "amber" | "rose";
  icon?: ReactNode;
}) {
  const tones = {
    default: "border-ink-200 bg-white",
    brand: "border-brand-200 bg-brand-50",
    teal: "border-teal-100 bg-teal-50",
    amber: "border-amber-100 bg-amber-50",
    rose: "border-rose-100 bg-rose-50",
  } as const;
  const valueTone = {
    default: "text-ink-900",
    brand: "text-brand-700",
    teal: "text-teal-700",
    amber: "text-amber-700",
    rose: "text-rose-700",
  } as const;

  // A stable hook for tests. Derived from the label so no call site has to
  // supply it, and it does not depend on CSS-uppercased rendered text.
  const testId = `stat-${label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")}`;

  return (
    <div data-testid={testId} className={clsx("rounded-xl border p-4 shadow-sm", tones[tone])}>
      <div className="flex items-start justify-between gap-2">
        <p className="text-[11px] font-semibold uppercase tracking-wider text-ink-500">{label}</p>
        {icon ? <span className="text-ink-400">{icon}</span> : null}
      </div>
      <p className={clsx("tabular mt-2 text-2xl font-semibold leading-none", valueTone[tone])}>{value}</p>
      {hint ? <p className="mt-2 text-[12px] leading-snug text-ink-500">{hint}</p> : null}
    </div>
  );
}

// -----------------------------------------------------------------------------
// Badges
// -----------------------------------------------------------------------------

export type BadgeTone = "neutral" | "brand" | "success" | "warning" | "danger" | "info";

export function Badge({
  children,
  tone = "neutral",
  className,
  title,
}: {
  children: ReactNode;
  tone?: BadgeTone;
  className?: string;
  title?: string;
}) {
  const tones: Record<BadgeTone, string> = {
    neutral: "bg-ink-100 text-ink-700 ring-ink-200",
    brand: "bg-brand-50 text-brand-700 ring-brand-200",
    success: "bg-teal-50 text-teal-700 ring-teal-100",
    warning: "bg-amber-50 text-amber-700 ring-amber-100",
    danger: "bg-rose-50 text-rose-700 ring-rose-100",
    info: "bg-ink-50 text-ink-600 ring-ink-200",
  };
  return (
    <span
      title={title}
      className={clsx(
        "inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-medium ring-1 ring-inset",
        tones[tone],
        className,
      )}
    >
      {children}
    </span>
  );
}

// -----------------------------------------------------------------------------
// Tables
// -----------------------------------------------------------------------------

export function TableShell({ children, className }: { children: ReactNode; className?: string }) {
  return (
    <div className={clsx("overflow-x-auto", className)}>
      <table className="w-full min-w-full border-collapse text-sm">{children}</table>
    </div>
  );
}

export function Th({
  children,
  className,
  align = "left",
  scope = "col",
}: {
  children?: ReactNode;
  className?: string;
  align?: "left" | "right" | "center";
  scope?: "col" | "row";
}) {
  return (
    <th
      scope={scope}
      className={clsx(
        "border-b border-ink-200 bg-ink-50 px-3 py-2 text-[11px] font-semibold uppercase tracking-wider text-ink-500",
        align === "right" && "text-right",
        align === "center" && "text-center",
        align === "left" && "text-left",
        className,
      )}
    >
      {children}
    </th>
  );
}

export function Td({
  children,
  className,
  align = "left",
  colSpan,
  title,
}: {
  children?: ReactNode;
  className?: string;
  align?: "left" | "right" | "center";
  colSpan?: number;
  title?: string;
}) {
  return (
    <td
      colSpan={colSpan}
      title={title}
      className={clsx(
        "border-b border-ink-100 px-3 py-2 align-middle text-ink-700",
        align === "right" && "text-right",
        align === "center" && "text-center",
        className,
      )}
    >
      {children}
    </td>
  );
}

// -----------------------------------------------------------------------------
// Empty / error states
// -----------------------------------------------------------------------------

export function EmptyState({
  title,
  description,
  action,
  icon,
}: {
  title: string;
  description?: ReactNode;
  action?: ReactNode;
  icon?: ReactNode;
}) {
  return (
    <div className="flex flex-col items-center justify-center px-6 py-14 text-center">
      {icon ? <div className="mb-3 text-ink-300">{icon}</div> : null}
      <h3 className="text-sm font-semibold text-ink-800">{title}</h3>
      {description ? <p className="mt-1.5 max-w-md text-[13px] leading-relaxed text-ink-500">{description}</p> : null}
      {action ? <div className="mt-4">{action}</div> : null}
    </div>
  );
}

export function Callout({
  tone = "info",
  title,
  children,
  actions,
}: {
  tone?: "info" | "warning" | "danger" | "success";
  title?: ReactNode;
  children?: ReactNode;
  actions?: ReactNode;
}) {
  const tones = {
    info: "border-brand-200 bg-brand-50 text-brand-800",
    warning: "border-amber-100 bg-amber-50 text-amber-700",
    danger: "border-rose-100 bg-rose-50 text-rose-700",
    success: "border-teal-100 bg-teal-50 text-teal-700",
  } as const;
  return (
    <div className={clsx("rounded-lg border px-4 py-3 text-[13px] leading-relaxed", tones[tone])}>
      {title ? <p className="font-semibold">{title}</p> : null}
      {children ? <div className={clsx(title && "mt-1")}>{children}</div> : null}
      {actions ? <div className="mt-3 flex flex-wrap gap-2">{actions}</div> : null}
    </div>
  );
}

// -----------------------------------------------------------------------------
// Form primitives
// -----------------------------------------------------------------------------

export const inputClass =
  "block w-full rounded-md border border-ink-200 bg-white px-3 py-1.5 text-sm text-ink-800 shadow-sm placeholder:text-ink-400 focus:border-brand-500 focus:outline-none focus:ring-1 focus:ring-brand-500 disabled:bg-ink-50 disabled:text-ink-500";

export const selectClass = clsx(inputClass, "pr-8");

export function Field({
  label,
  htmlFor,
  hint,
  error,
  required,
  children,
  className,
}: {
  label: ReactNode;
  htmlFor?: string;
  hint?: ReactNode;
  error?: string | null;
  required?: boolean;
  children: ReactNode;
  className?: string;
}) {
  return (
    <div className={clsx("space-y-1", className)}>
      <label htmlFor={htmlFor} className="block text-[12px] font-medium text-ink-700">
        {label}
        {required ? (
          <span aria-hidden className="ml-0.5 text-rose-600">
            *
          </span>
        ) : null}
        {required ? <span className="sr-only"> (required)</span> : null}
      </label>
      {children}
      {error ? (
        <p className="text-[12px] font-medium text-rose-600" role="alert">
          {error}
        </p>
      ) : hint ? (
        <p className="text-[12px] text-ink-500">{hint}</p>
      ) : null}
    </div>
  );
}

export function DescriptionList({
  items,
  columns = 2,
}: {
  items: { label: string; value: ReactNode }[];
  columns?: 1 | 2 | 3 | 4;
}) {
  const cols = {
    1: "sm:grid-cols-1",
    2: "sm:grid-cols-2",
    3: "sm:grid-cols-2 lg:grid-cols-3",
    4: "sm:grid-cols-2 lg:grid-cols-4",
  } as const;
  return (
    <dl className={clsx("grid grid-cols-1 gap-x-6 gap-y-4", cols[columns])}>
      {items.map((item) => (
        <div key={item.label}>
          <dt className="text-[11px] font-semibold uppercase tracking-wider text-ink-500">{item.label}</dt>
          <dd className="mt-0.5 text-sm text-ink-800">{item.value || <span className="text-ink-400">—</span>}</dd>
        </div>
      ))}
    </dl>
  );
}

// -----------------------------------------------------------------------------
// Loading skeletons
// -----------------------------------------------------------------------------

export function SkeletonRows({ rows = 6, columns = 5 }: { rows?: number; columns?: number }) {
  return (
    <div className="space-y-2 p-4">
      {Array.from({ length: rows }).map((_, rowIndex) => (
        <div key={rowIndex} className="flex gap-3">
          {Array.from({ length: columns }).map((__, columnIndex) => (
            <div
              key={columnIndex}
              className="skeleton h-5 flex-1 rounded"
              style={{ maxWidth: columnIndex === 0 ? "9rem" : undefined }}
            />
          ))}
        </div>
      ))}
    </div>
  );
}

export function ProgressBar({
  value,
  tone = "brand",
  label,
}: {
  value: number;
  tone?: "brand" | "teal" | "amber";
  label?: string;
}) {
  const clamped = Math.max(0, Math.min(100, value));
  const tones = { brand: "bg-brand-600", teal: "bg-teal-600", amber: "bg-amber-600" } as const;
  return (
    <div
      className="h-1.5 w-full overflow-hidden rounded-full bg-ink-100"
      role="progressbar"
      aria-valuenow={Math.round(clamped)}
      aria-valuemin={0}
      aria-valuemax={100}
      aria-label={label ?? "Completion"}
    >
      <div className={clsx("h-full rounded-full transition-all", tones[tone])} style={{ width: `${clamped}%` }} />
    </div>
  );
}
