import { type ReactNode, type TextareaHTMLAttributes, type InputHTMLAttributes } from 'react';

import {
    formControlClassName,
    formErrorClassName,
    formFieldClassName,
    formHelpClassName,
    formLabelClassName,
} from '@admin/components/ui/field-styles';
import { cn } from '@admin/lib/utils';

type FormGroupProps = {
    id?: string;
    label: string;
    error?: string;
    helpText?: string;
    children?: ReactNode;
} & (
    | {
          as?: 'input';
          inputProps?: InputHTMLAttributes<HTMLInputElement>;
      }
    | {
          as: 'textarea';
          inputProps?: TextareaHTMLAttributes<HTMLTextAreaElement>;
      }
);

export function FormGroup({ id, label, error, helpText, as = 'input', children, ...rest }: FormGroupProps) {
    const inputId = id ?? label.toLowerCase().replace(/\s+/g, '-');
    const invalidClass = error ? '!border-danger focus:border-danger focus:ring-danger' : '';

    return (
        <div className={cn(formFieldClassName, 'mb-4')}>
            <label htmlFor={inputId} className={formLabelClassName}>
                {label}
            </label>
            {children ??
                (as === 'textarea' ? (
                    <textarea
                        id={inputId}
                        className={cn(
                            formControlClassName,
                            invalidClass,
                            (rest as { inputProps?: TextareaHTMLAttributes<HTMLTextAreaElement> }).inputProps?.className,
                        )}
                        aria-invalid={Boolean(error)}
                        aria-describedby={error ? `${inputId}-error` : helpText ? `${inputId}-help` : undefined}
                        {...(rest as { inputProps?: TextareaHTMLAttributes<HTMLTextAreaElement> }).inputProps}
                    />
                ) : (
                    <input
                        id={inputId}
                        className={cn(
                            formControlClassName,
                            invalidClass,
                            (rest as { inputProps?: InputHTMLAttributes<HTMLInputElement> }).inputProps?.className,
                        )}
                        aria-invalid={Boolean(error)}
                        aria-describedby={error ? `${inputId}-error` : helpText ? `${inputId}-help` : undefined}
                        {...(rest as { inputProps?: InputHTMLAttributes<HTMLInputElement> }).inputProps}
                    />
                ))}
            {error && (
                <span id={`${inputId}-error`} className={formErrorClassName}>
                    {error}
                </span>
            )}
            {helpText && !error && (
                <p id={`${inputId}-help`} className={formHelpClassName}>
                    {helpText}
                </p>
            )}
        </div>
    );
}
