"use client";

import { forwardRef, useState, type ReactNode } from "react";
import { cn } from "@/lib/utils";
import { Eye, EyeOff } from "lucide-react";

/**
 * Accessible floating-label fields (spec §41–47).
 *
 * The label is a real <label htmlFor>. The float is CSS-only via a `placeholder=" "`
 * + `peer-placeholder-shown` — so it also floats for prefilled and autofilled
 * values (which are not placeholder-shown). aria-invalid / aria-describedby wire
 * the error + helper text to the field for screen readers.
 */

const fieldBase =
  "peer w-full rounded-xl border bg-background text-sm text-foreground shadow-2xs transition-[border-color,box-shadow,background-color] duration-200 placeholder:text-transparent focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:opacity-55";

const fieldTone = (error?: boolean) =>
  error
    ? "border-destructive focus:border-destructive focus:ring-destructive/60 aria-[invalid=true]:border-destructive"
    : "border-border hover:border-foreground/30 focus:border-foreground focus:ring-foreground/70";

const labelBase =
  "pointer-events-none absolute left-3.5 top-2 z-[1] origin-left text-[11px] font-medium text-muted-foreground transition-all duration-200 ease-out";

// Empty + unfocused → centered placeholder position; focus/filled → floated.
const labelFloat =
  "peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:text-sm peer-placeholder-shown:font-normal peer-focus:top-2 peer-focus:translate-y-0 peer-focus:text-[11px] peer-focus:font-medium";

function Messages({
  id,
  error,
  helper,
}: {
  id: string;
  error?: string;
  helper?: ReactNode;
}) {
  if (error) {
    return (
      <p
        id={`${id}-error`}
        role="alert"
        className="mt-1.5 flex items-start gap-1.5 text-xs font-medium text-destructive motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-top-1"
      >
        {error}
      </p>
    );
  }
  if (helper) {
    return (
      <p id={`${id}-help`} className="mt-1.5 text-xs text-muted-foreground">
        {helper}
      </p>
    );
  }
  return null;
}

export interface FloatingInputProps extends React.ComponentPropsWithoutRef<"input"> {
  id: string;
  label: string;
  error?: string;
  helper?: ReactNode;
  showPasswordToggle?: boolean;
}

export const FloatingInput = forwardRef<HTMLInputElement, FloatingInputProps>(
  function FloatingInput(
    { id, label, error, helper, className, type = "text", showPasswordToggle, ...props },
    ref
  ) {
    const describedBy = error ? `${id}-error` : helper ? `${id}-help` : undefined;
    const [showPassword, setShowPassword] = useState(false);
    const isPassword = type === "password";
    const resolvedType = isPassword && showPasswordToggle ? (showPassword ? "text" : "password") : type;

    return (
      <div>
        <div className="relative">
          <input
            id={id}
            ref={ref}
            type={resolvedType}
            placeholder=" "
            aria-invalid={error ? true : undefined}
            aria-describedby={describedBy}
            className={cn(
              fieldBase,
              "h-14 px-3.5 pb-1.5 pt-5",
              showPasswordToggle && isPassword && "pr-11",
              fieldTone(!!error),
              className
            )}
            {...props}
          />
          <label
            htmlFor={id}
            className={cn(
              labelBase,
              labelFloat,
              error ? "text-destructive" : "peer-focus:text-foreground"
            )}
          >
            {label}
          </label>
          {showPasswordToggle && isPassword && (
            <button
              type="button"
              onClick={() => setShowPassword((prev) => !prev)}
              aria-label={showPassword ? "Hide password" : "Show password"}
              className="absolute right-3.5 top-1/2 -translate-y-1/2 z-[2] rounded-md p-1 text-muted-foreground transition-colors hover:text-foreground focus:outline-none focus:ring-1 focus:ring-foreground"
            >
              {showPassword ? (
                <EyeOff className="size-4" aria-hidden="true" />
              ) : (
                <Eye className="size-4" aria-hidden="true" />
              )}
            </button>
          )}
        </div>
        <Messages id={id} error={error} helper={helper} />
      </div>
    );
  }
);

export const FloatingPasswordInput = forwardRef<
  HTMLInputElement,
  Omit<FloatingInputProps, "type">
>(function FloatingPasswordInput(props, ref) {
  return <FloatingInput ref={ref} type="password" showPasswordToggle {...props} />;
});

interface FloatingTextareaProps extends React.ComponentPropsWithoutRef<"textarea"> {
  id: string;
  label: string;
  error?: string;
  helper?: ReactNode;
}

export const FloatingTextarea = forwardRef<HTMLTextAreaElement, FloatingTextareaProps>(
  function FloatingTextarea({ id, label, error, helper, className, rows = 4, ...props }, ref) {
    const describedBy = error ? `${id}-error` : helper ? `${id}-help` : undefined;
    return (
      <div>
        <div className="relative">
          <textarea
            id={id}
            ref={ref}
            rows={rows}
            placeholder=" "
            aria-invalid={error ? true : undefined}
            aria-describedby={describedBy}
            className={cn(fieldBase, "resize-none px-3.5 pb-2.5 pt-6", fieldTone(!!error), className)}
            {...props}
          />
          {/* Textarea label rests near the top rather than vertically centered. */}
          <label
            htmlFor={id}
            className={cn(
              "pointer-events-none absolute left-3.5 top-2.5 z-[1] text-[11px] font-medium text-muted-foreground transition-all duration-200 ease-out",
              "peer-placeholder-shown:top-4 peer-placeholder-shown:text-sm peer-placeholder-shown:font-normal peer-focus:top-2.5 peer-focus:text-[11px] peer-focus:font-medium",
              error ? "text-destructive" : "peer-focus:text-foreground",
            )}
          >
            {label}
          </label>
        </div>
        <Messages id={id} error={error} helper={helper} />
      </div>
    );
  },
);
