/**
 * 现代化表单组件
 * 提供统一的表单样式和验证功能
 */

import React, { createContext, useContext, forwardRef } from 'react';
import { cn } from '../../utils/cn';
import { Input, type InputProps } from './Input';
import { Button, type ButtonProps } from './Button';

// ==================== 表单上下文 ====================

interface FormContextValue {
  errors: Record<string, string>;
  touched: Record<string, boolean>;
  isSubmitting: boolean;
}

const FormContext = createContext<FormContextValue | null>(null);

const useFormContext = () => {
  const context = useContext(FormContext);
  if (!context) {
    throw new Error('Form components must be used within a Form');
  }
  return context;
};

// ==================== 表单组件 ====================

export interface FormProps extends React.FormHTMLAttributes<HTMLFormElement> {
  errors?: Record<string, string>;
  touched?: Record<string, boolean>;
  isSubmitting?: boolean;
}

export const Form = forwardRef<HTMLFormElement, FormProps>(
  ({ 
    className, 
    errors = {}, 
    touched = {}, 
    isSubmitting = false, 
    children, 
    ...props 
  }, ref) => {
    const contextValue: FormContextValue = {
      errors,
      touched,
      isSubmitting,
    };

    return (
      <FormContext.Provider value={contextValue}>
        <form
          ref={ref}
          className={cn('space-y-6', className)}
          {...props}
        >
          {children}
        </form>
      </FormContext.Provider>
    );
  }
);

Form.displayName = 'Form';

// ==================== 表单字段组件 ====================

export interface FormFieldProps {
  name: string;
  label?: string;
  required?: boolean;
  children: React.ReactNode;
  className?: string;
}

export const FormField: React.FC<FormFieldProps> = ({
  name,
  label,
  required,
  children,
  className,
}) => {
  const { errors, touched } = useFormContext();
  const error = touched[name] ? errors[name] : undefined;

  return (
    <div className={cn('space-y-2', className)}>
      {label && (
        <label className="block text-sm font-medium text-gray-700">
          {label}
          {required && <span className="text-red-500 ml-1">*</span>}
        </label>
      )}
      
      <div className="relative">
        {React.cloneElement(children as React.ReactElement, {
          error,
          'aria-invalid': error ? 'true' : 'false',
          'aria-describedby': error ? `${name}-error` : undefined,
        })}
      </div>
      
      {error && (
        <p id={`${name}-error`} className="text-sm text-red-600">
          {error}
        </p>
      )}
    </div>
  );
};

// ==================== 表单输入组件 ====================

export interface FormInputProps extends Omit<InputProps, 'error'> {
  name: string;
}

export const FormInput = forwardRef<HTMLInputElement, FormInputProps>(
  ({ name, ...props }, ref) => {
    const { errors, touched } = useFormContext();
    const error = touched[name] ? errors[name] : undefined;

    return (
      <Input
        ref={ref}
        error={error}
        {...props}
      />
    );
  }
);

FormInput.displayName = 'FormInput';

// ==================== 表单选择组件 ====================

export interface FormSelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {
  name: string;
  options: Array<{ value: string; label: string; disabled?: boolean }>;
  placeholder?: string;
  error?: string;
}

export const FormSelect = forwardRef<HTMLSelectElement, FormSelectProps>(
  ({ 
    name, 
    options, 
    placeholder, 
    className, 
    ...props 
  }, ref) => {
    const { errors, touched } = useFormContext();
    const error = touched[name] ? errors[name] : undefined;

    return (
      <div className="relative">
        <select
          ref={ref}
          name={name}
          className={cn(
            'flex w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm',
            'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500',
            'disabled:cursor-not-allowed disabled:opacity-50',
            'transition-all duration-200',
            error && 'border-red-300 focus:ring-red-500 focus:border-red-500',
            className
          )}
          aria-invalid={error ? 'true' : 'false'}
          aria-describedby={error ? `${name}-error` : undefined}
          {...props}
        >
          {placeholder && (
            <option value="" disabled>
              {placeholder}
            </option>
          )}
          {options.map((option) => (
            <option
              key={option.value}
              value={option.value}
              disabled={option.disabled}
            >
              {option.label}
            </option>
          ))}
        </select>
        
        {error && (
          <p id={`${name}-error`} className="mt-1 text-sm text-red-600">
            {error}
          </p>
        )}
      </div>
    );
  }
);

FormSelect.displayName = 'FormSelect';

// ==================== 表单文本域组件 ====================

export interface FormTextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
  name: string;
  error?: string;
}

export const FormTextarea = forwardRef<HTMLTextAreaElement, FormTextareaProps>(
  ({ 
    name, 
    className, 
    ...props 
  }, ref) => {
    const { errors, touched } = useFormContext();
    const error = touched[name] ? errors[name] : undefined;

    return (
      <div>
        <textarea
          ref={ref}
          name={name}
          className={cn(
            'flex w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm',
            'placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500',
            'disabled:cursor-not-allowed disabled:opacity-50',
            'transition-all duration-200 resize-vertical',
            error && 'border-red-300 focus:ring-red-500 focus:border-red-500',
            className
          )}
          aria-invalid={error ? 'true' : 'false'}
          aria-describedby={error ? `${name}-error` : undefined}
          {...props}
        />
        
        {error && (
          <p id={`${name}-error`} className="mt-1 text-sm text-red-600">
            {error}
          </p>
        )}
      </div>
    );
  }
);

FormTextarea.displayName = 'FormTextarea';

// ==================== 表单复选框组件 ====================

export interface FormCheckboxProps extends React.InputHTMLAttributes<HTMLInputElement> {
  name: string;
  label: string;
  description?: string;
}

export const FormCheckbox = forwardRef<HTMLInputElement, FormCheckboxProps>(
  ({ 
    name, 
    label, 
    description, 
    className, 
    ...props 
  }, ref) => {
    const { errors, touched } = useFormContext();
    const error = touched[name] ? errors[name] : undefined;

    return (
      <div className={cn('space-y-2', className)}>
        <div className="flex items-start space-x-3">
          <input
            ref={ref}
            type="checkbox"
            name={name}
            className={cn(
              'w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500 focus:ring-2',
              'disabled:cursor-not-allowed disabled:opacity-50',
              error && 'border-red-300 focus:ring-red-500',
              'mt-0.5'
            )}
            aria-invalid={error ? 'true' : 'false'}
            aria-describedby={error ? `${name}-error` : undefined}
            {...props}
          />
          
          <div className="flex-1">
            <label className="text-sm font-medium text-gray-700">
              {label}
            </label>
            {description && (
              <p className="text-sm text-gray-500 mt-1">{description}</p>
            )}
          </div>
        </div>
        
        {error && (
          <p id={`${name}-error`} className="text-sm text-red-600">
            {error}
          </p>
        )}
      </div>
    );
  }
);

FormCheckbox.displayName = 'FormCheckbox';

// ==================== 表单提交按钮 ====================

export interface FormSubmitButtonProps extends ButtonProps {
  loadingText?: string;
}

export const FormSubmitButton = forwardRef<HTMLButtonElement, FormSubmitButtonProps>(
  ({ 
    children, 
    loadingText = '提交中...', 
    ...props 
  }, ref) => {
    const { isSubmitting } = useFormContext();

    return (
      <Button
        ref={ref}
        type="submit"
        loading={isSubmitting}
        disabled={isSubmitting}
        {...props}
      >
        {isSubmitting ? loadingText : children}
      </Button>
    );
  }
);

FormSubmitButton.displayName = 'FormSubmitButton';

// ==================== 表单组 ====================

export interface FormGroupProps {
  title: string;
  description?: string;
  children: React.ReactNode;
  className?: string;
}

export const FormGroup: React.FC<FormGroupProps> = ({
  title,
  description,
  children,
  className,
}) => (
  <div className={cn('space-y-4', className)}>
    <div>
      <h3 className="text-lg font-medium text-gray-900">{title}</h3>
      {description && (
        <p className="text-sm text-gray-500 mt-1">{description}</p>
      )}
    </div>
    <div className="space-y-4">
      {children}
    </div>
  </div>
);
