import type { InputHTMLAttributes, ReactNode, SelectHTMLAttributes } from "react";

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

const FIELD_BASE =
  "w-full rounded-md border border-line bg-surface-2/60 px-4 text-sm text-ink placeholder:text-ink-faint " +
  "transition-colors duration-200 outline-none focus:border-brand-500/70 focus:bg-surface-2 " +
  "disabled:opacity-60";

export function Field({
  label,
  hint,
  error,
  htmlFor,
  children,
  className,
}: {
  label?: ReactNode;
  hint?: ReactNode;
  error?: string;
  htmlFor?: string;
  children: ReactNode;
  className?: string;
}) {
  return (
    <div className={cn("space-y-1.5", className)}>
      {label ? (
        <label htmlFor={htmlFor} className="block text-[13px] font-semibold text-ink-soft">
          {label}
        </label>
      ) : null}
      {children}
      {error ? (
        <p className="text-[12px] font-medium text-brand-400" role="alert">
          {error}
        </p>
      ) : hint ? (
        <p className="text-[12px] text-ink-muted">{hint}</p>
      ) : null}
    </div>
  );
}

export function Input({
  className,
  invalid,
  ...rest
}: InputHTMLAttributes<HTMLInputElement> & { invalid?: boolean }) {
  return (
    <input
      className={cn(FIELD_BASE, "h-12", invalid && "border-brand-500/70", className)}
      aria-invalid={invalid || undefined}
      {...rest}
    />
  );
}

export function Select({
  className,
  children,
  ...rest
}: SelectHTMLAttributes<HTMLSelectElement>) {
  return (
    <select className={cn(FIELD_BASE, "h-12 cursor-pointer pr-10 appearance-none", className)} {...rest}>
      {children}
    </select>
  );
}

export function Switch({
  checked,
  onChange,
  label,
  description,
  disabled,
}: {
  checked: boolean;
  onChange: (next: boolean) => void;
  label: ReactNode;
  description?: ReactNode;
  disabled?: boolean;
}) {
  return (
    <label
      className={cn(
        "flex cursor-pointer items-center justify-between gap-4 py-3",
        disabled && "cursor-not-allowed opacity-60",
      )}
    >
      <span className="min-w-0">
        <span className="block text-sm font-semibold text-ink">{label}</span>
        {description ? (
          <span className="mt-0.5 block text-[12px] text-ink-muted">{description}</span>
        ) : null}
      </span>
      <button
        type="button"
        role="switch"
        aria-checked={checked}
        aria-label={typeof label === "string" ? label : "Toggle"}
        disabled={disabled}
        onClick={() => !disabled && onChange(!checked)}
        className={cn(
          "relative h-[26px] w-[46px] shrink-0 rounded-pill border transition-colors duration-300",
          checked
            ? "border-brand-500/60 bg-brand-500/85"
            : "border-line bg-surface-3",
        )}
      >
        <span
          className={cn(
            "absolute top-1/2 h-[18px] w-[18px] -translate-y-1/2 rounded-full bg-white shadow-md",
            "transition-[left] duration-300 ease-[cubic-bezier(0.25,0.46,0.45,0.94)]",
            checked ? "left-[25px]" : "left-[3px]",
          )}
        />
      </button>
    </label>
  );
}

export function Alert({
  tone = "error",
  children,
  className,
}: {
  tone?: "error" | "success" | "info";
  children: ReactNode;
  className?: string;
}) {
  return (
    <div
      role={tone === "error" ? "alert" : "status"}
      className={cn(
        "rounded-md px-3.5 py-2.5 text-[13px] font-medium ring-1",
        tone === "error" && "bg-brand-500/12 text-brand-300 ring-brand-500/25",
        tone === "success" && "bg-emerald-500/12 text-emerald-300 ring-emerald-500/25",
        tone === "info" && "bg-sky-500/12 text-sky-300 ring-sky-500/25",
        className,
      )}
    >
      {children}
    </div>
  );
}
