import { clsx } from "clsx";

const controlClasses =
  "w-full rounded-md border border-[var(--color-line)] bg-white px-3 py-2 text-[14px] text-[var(--color-ink)] placeholder:text-[var(--color-slate)]/70 shadow-[inset_0_1px_0_rgba(10,15,46,0.02)] transition-colors focus:border-[var(--color-blue)] focus:outline-none focus:ring-2 focus:ring-[var(--color-mist)] disabled:cursor-not-allowed disabled:bg-[var(--color-line)]/40";

type FieldShellProps = {
  label?: string;
  hint?: string;
  error?: string;
  required?: boolean;
  htmlFor?: string;
  className?: string;
  children: React.ReactNode;
};

export function FieldShell({
  label,
  hint,
  error,
  required,
  htmlFor,
  className,
  children,
}: FieldShellProps) {
  return (
    <div className={clsx("flex flex-col gap-1.5", className)}>
      {label && (
        <label
          htmlFor={htmlFor}
          className="text-[11px] font-bold uppercase tracking-wider text-[var(--color-slate)]"
        >
          {label}
          {required && <span className="ml-1 text-[var(--color-blue)]">*</span>}
        </label>
      )}
      {children}
      {hint && !error && (
        <p className="text-[12px] text-[var(--color-slate)]">{hint}</p>
      )}
      {error && <p className="text-[12px] font-medium text-red-600">{error}</p>}
    </div>
  );
}

type InputProps = React.InputHTMLAttributes<HTMLInputElement> & {
  label?: string;
  hint?: string;
  error?: string;
  wrapClassName?: string;
};

export function InputField({
  label,
  hint,
  error,
  wrapClassName,
  className,
  id,
  required,
  ...rest
}: InputProps) {
  return (
    <FieldShell
      label={label}
      hint={hint}
      error={error}
      required={required}
      htmlFor={id}
      className={wrapClassName}
    >
      <input
        id={id}
        required={required}
        className={clsx(
          controlClasses,
          error && "border-red-400 focus:border-red-500 focus:ring-red-100",
          className,
        )}
        {...rest}
      />
    </FieldShell>
  );
}

type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement> & {
  label?: string;
  hint?: string;
  error?: string;
  wrapClassName?: string;
};

export function TextareaField({
  label,
  hint,
  error,
  wrapClassName,
  className,
  id,
  required,
  rows = 4,
  ...rest
}: TextareaProps) {
  return (
    <FieldShell
      label={label}
      hint={hint}
      error={error}
      required={required}
      htmlFor={id}
      className={wrapClassName}
    >
      <textarea
        id={id}
        required={required}
        rows={rows}
        className={clsx(
          controlClasses,
          "resize-y leading-relaxed",
          error && "border-red-400 focus:border-red-500 focus:ring-red-100",
          className,
        )}
        {...rest}
      />
    </FieldShell>
  );
}

type SelectProps = React.SelectHTMLAttributes<HTMLSelectElement> & {
  label?: string;
  hint?: string;
  error?: string;
  wrapClassName?: string;
  options?: Array<{ value: string; label: string }>;
};

export function SelectField({
  label,
  hint,
  error,
  wrapClassName,
  className,
  id,
  required,
  options,
  children,
  ...rest
}: SelectProps) {
  return (
    <FieldShell
      label={label}
      hint={hint}
      error={error}
      required={required}
      htmlFor={id}
      className={wrapClassName}
    >
      <select
        id={id}
        required={required}
        className={clsx(
          controlClasses,
          "appearance-none bg-[url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2212%22%20height%3D%2212%22%20viewBox%3D%220%200%2012%2012%22%20fill%3D%22none%22%20stroke%3D%22%234a5280%22%20stroke-width%3D%221.5%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpolyline%20points%3D%223%2C5%206%2C8%209%2C5%22%2F%3E%3C%2Fsvg%3E')] bg-[length:12px_12px] bg-[right_0.75rem_center] bg-no-repeat pr-9",
          error && "border-red-400 focus:border-red-500 focus:ring-red-100",
          className,
        )}
        {...rest}
      >
        {options
          ? options.map((o) => (
              <option key={o.value} value={o.value}>
                {o.label}
              </option>
            ))
          : children}
      </select>
    </FieldShell>
  );
}
