import * as React from "react";
import { cn } from "../lib/cn";
import { Label } from "./label";

export interface FormFieldProps {
  label: React.ReactNode;
  children: React.ReactElement<{
    id?: string;
    "aria-describedby"?: string;
    "aria-invalid"?: boolean;
  }>;
  id?: string;
  description?: React.ReactNode;
  error?: React.ReactNode;
  required?: boolean;
  className?: string;
}

/** Associates a control with its label, supporting text, and validation error. */
export function FormField({
  label,
  children,
  id,
  description,
  error,
  required,
  className,
}: FormFieldProps) {
  const generatedId = React.useId();
  const controlId = id ?? children.props.id ?? `field-${generatedId}`;
  const descriptionId = description ? `${controlId}-description` : undefined;
  const errorId = error ? `${controlId}-error` : undefined;
  const describedBy = [children.props["aria-describedby"], descriptionId, errorId].filter(Boolean).join(" ") || undefined;

  return (
    <div className={cn("space-y-1.5", className)}>
      <Label htmlFor={controlId} className="mb-0 text-sm text-text">
        {label}
        {required && <span className="ml-1 text-danger" aria-hidden>*</span>}
      </Label>
      {React.cloneElement(children, {
        id: controlId,
        "aria-describedby": describedBy,
        "aria-invalid": Boolean(error) || children.props["aria-invalid"],
      })}
      {description && !error && <p id={descriptionId} className="text-xs text-muted">{description}</p>}
      {error && <p id={errorId} className="text-xs font-medium text-danger">{error}</p>}
    </div>
  );
}
