/**
 * Defines types and interfaces for conditional field rendering and validation.
 * This module provides the type definitions for dynamically showing, hiding,
 * and validating fields based on form values.
 */
import { UseFormRegisterReturn } from 'react-hook-form';
import { FormGroup } from '../../core/form/form-groups';

/**
 * Base props for conditional rendering components
 * Contains properties to determine visibility and validation status
 */
export interface ConditionalRenderProps {
  /** Whether the field or component should be displayed */
  shouldShow: boolean;

  /** Whether validation should be applied even when hidden */
  shouldValidate: boolean;

  /**
   * Helper function to conditionally render a component
   *
   * @param component - The React component to conditionally render
   * @returns The component if condition is met, otherwise null
   *
   * @example
   * // Render a field only when user selects "Other" option
   * const { render } = when(groupIndex, data => data.selection === 'other');
   *
   * return (
   *   <>
   *     <SelectField name="selection" options={options} />
   *     {render(<TextField name="otherDetails" label="Please specify" />)}
   *   </>
   * );
   */
  render: (component: React.ReactNode) => React.ReactNode | null;
}

/**
 * Extended conditional rendering props for group-specific conditions
 * Includes methods for conditional field registration and validation
 *
 * @template T - The type of form data
 */
export interface GroupConditionalRenderProps<T> extends ConditionalRenderProps {
  /**
   * Conditionally registers a field with React Hook Form
   * If the condition is not met, either returns a dummy register object
   * or clears the field value based on options
   *
   * @template K - The key of the field to register
   * @param fieldName - The name of the field to register
   * @param options - Registration options passed to React Hook Form
   * @returns Either a real or dummy registration object
   *
   * @example
   * // Register a field only when the user is employed
   * const { registerIf } = when(groupIndex, data => data.employmentStatus === 'employed');
   *
   * return (
   *   <input
   *     {...registerIf('employerName', { required: 'Employer name is required' })}
   *     placeholder="Employer name"
   *   />
   * );
   */
  registerIf: <K extends keyof T>(
    fieldName: K,
    options?: any
  ) =>
    | UseFormRegisterReturn
    | {
        name: string;
        onChange: () => void;
        onBlur: () => void;
        ref: () => void;
      };

  /**
   * Conditionally validates a field based on the condition
   * If the condition is not met and validateWhenHidden is false,
   * validation is skipped
   *
   * @template K - The key of the field to validate
   * @param fieldName - The name of the field to validate
   * @param validationFn - Function that validates the field value
   * @returns Validation error message or undefined if valid/skipped
   *
   * @example
   * // Validate a field only when a checkbox is checked
   * const { validateIf } = when(groupIndex, data => data.needsVerification);
   *
   * const error = validateIf('verificationCode',
   *   value => value?.length !== 6 ? 'Code must be 6 digits' : undefined
   * );
   *
   * if (error) {
   *   setError(error);
   * }
   */
  validateIf: <K extends keyof T>(
    fieldName: K,
    validationFn: (value: T[K]) => string | undefined
  ) => string | undefined;
}

/**
 * Interface for managing conditional fields within a form
 * Provides methods to show/hide fields based on conditions
 *
 * @template T - The type of form data
 */
export interface ConditionalFieldsManager<T> {
  /**
   * Creates a condition based on values within a specific group
   *
   * @param groupIndex - The index of the group to evaluate
   * @param condition - Function that determines if condition is met
   * @param options - Configuration options for hidden fields
   * @returns Object with conditional rendering and validation helpers
   *
   * @example
   * // Show additional fields based on selection
   * const { when } = useReform(formConfig);
   *
   * const { render, registerIf } = when(
   *   0, // first group
   *   data => data.hasChildren === true,
   *   { clearWhenHidden: true }
   * );
   *
   * return (
   *   <form>
   *     <Checkbox {...register('hasChildren')} label="Do you have children?" />
   *
   *     {render(
   *       <div>
   *         <NumberInput
   *           {...registerIf('childrenCount', { min: 1 })}
   *           label="How many children?"
   *         />
   *       </div>
   *     )}
   *   </form>
   * );
   *
   * @example
   * // Show payment details only when payment method is credit card
   * const { render, registerIf } = when(
   *   0,
   *   data => data.paymentMethod === 'creditCard',
   *   { clearWhenHidden: true }
   * );
   *
   * return (
   *   <div>
   *     <SelectField
   *       name="paymentMethod"
   *       options={['creditCard', 'bankTransfer', 'paypal']}
   *     />
   *
   *     {render(
   *       <div className="credit-card-fields">
   *         <TextField {...registerIf('cardNumber')} label="Card Number" />
   *         <TextField {...registerIf('cardName')} label="Name on Card" />
   *         <div className="flex">
   *           <TextField {...registerIf('expiryDate')} label="Expiry Date" />
   *           <TextField {...registerIf('cvv')} label="CVV" />
   *         </div>
   *       </div>
   *     )}
   *   </div>
   * );
   */
  when: (
    groupIndex: number,
    condition: (groupData: T) => boolean,
    options?: {
      /** Whether to clear field values when hidden (default: true) */
      clearWhenHidden?: boolean;
      /** Whether to validate fields even when hidden (default: false) */
      validateWhenHidden?: boolean;
    }
  ) => GroupConditionalRenderProps<T>;

  /**
   * Creates a condition based on values across all groups
   *
   * @param condition - Function that determines if condition is met
   * @param options - Configuration options for hidden fields
   * @returns Object with conditional rendering helpers
   *
   * @example
   * // Show a summary section only when all groups have data
   * const { whenAny } = useReform(formConfig);
   *
   * const { render } = whenAny(
   *   groups => groups.every(group =>
   *     group.data.firstName && group.data.lastName
   *   )
   * );
   *
   * return (
   *   <>
   *     {render(
   *       <SummarySection groups={groups} />
   *     )}
   *   </>
   * );
   *
   * @example
   * // Show summary section only when all required fields are filled
   * const { render } = whenAny(groups => {
   *   return groups.every(group =>
   *     group.data.firstName &&
   *     group.data.lastName &&
   *     group.data.email
   *   );
   * });
   *
   * return (
   *   <div>
   *     {render(
   *       <div className="summary-panel">
   *         <h2>Summary</h2>
   *         <SummaryTable data={groups} />
   *         <SubmitButton />
   *       </div>
   *     )}
   *   </div>
   * );
   */
  whenAny: (
    condition: (allGroups: FormGroup<T>[]) => boolean,
    options?: {
      /** Whether to clear field values when hidden (default: true) */
      clearWhenHidden?: boolean;
      /** Whether to validate fields even when hidden (default: false) */
      validateWhenHidden?: boolean;
    }
  ) => ConditionalRenderProps;

  /**
   * Creates a condition that depends on values from multiple groups and the entire form state
   *
   * @param condition - Function that evaluates condition based on all form data
   * @returns Object with conditional rendering helpers
   *
   * @example
   * // Show a component only when total participants across all groups exceeds 10
   * const { whenCross } = useReform(formConfig);
   *
   * const { render } = whenCross(formData => {
   *   const totalParticipants = formData.groups.reduce(
   *     (sum, group) => sum + (group.data.participants || 0),
   *     0
   *   );
   *   return totalParticipants > 10;
   * });
   *
   * return (
   *   <div>
   *     {render(
   *       <div className="large-group-notice">
   *         <Alert severity="info">
   *           For groups larger than 10, please contact our group sales department.
   *         </Alert>
   *         <Button>Contact Sales</Button>
   *       </div>
   *     )}
   *   </div>
   * );
   *
   * @example
   * // Show discount information when order total exceeds threshold
   * const { render } = whenCross(formData => {
   *   const orderTotal = formData.groups.reduce((sum, group) => {
   *     return sum + calculateGroupTotal(group.data);
   *   }, 0);
   *
   *   return orderTotal > 1000;
   * });
   *
   * return (
   *   <>
   *     {render(
   *       <DiscountBanner message="You qualify for a 10% bulk discount!" />
   *     )}
   *   </>
   * );
   */
  whenCross: (
    condition: (formData: { groups: FormGroup<T>[] }) => boolean
  ) => ConditionalRenderProps;

  /**
   * Creates a dependency tracking function that runs effects when specific fields change
   *
   * @template K - The keys of fields to track
   * @param groupIndex - The index of the group containing the fields
   * @param dependencies - Array of field names to track
   * @param effect - Function to run when dependencies change
   *
   * @example
   * // Update total price when quantity or price changes
   * const { createDependencyTracker } = useReform(formConfig);
   *
   * createDependencyTracker(
   *   groupIndex,
   *   ['quantity', 'unitPrice'],
   *   ({ quantity, unitPrice }) => {
   *     const total = (quantity || 0) * (unitPrice || 0);
   *     setValue(groupIndex, 'totalPrice', total);
   *   }
   * );
   *
   * @example
   * // Calculate total when quantity or price changes
   * createDependencyTracker(
   *   0,
   *   ['quantity', 'price'],
   *   ({ quantity, price }) => {
   *     const total = (quantity || 0) * (price || 0);
   *     setValue(0, 'total', total);
   *   }
   * );
   *
   * @example
   * // Update shipping options based on country selection
   * createDependencyTracker(
   *   groupIndex,
   *   ['country'],
   *   ({ country }) => {
   *     if (country) {
   *       const shippingOptions = getShippingOptionsForCountry(country);
   *       setShippingOptions(shippingOptions);
   *
   *       // Reset shipping method if not available in new country
   *       const currentMethod = getValue(groupIndex, 'shippingMethod');
   *       if (currentMethod && !shippingOptions.includes(currentMethod)) {
   *         setValue(groupIndex, 'shippingMethod', '');
   *       }
   *     }
   *   }
   * );
   */
  createDependencyTracker: <K extends keyof T>(
    groupIndex: number,
    dependencies: K[],
    effect: (values: Pick<T, K>) => void
  ) => void;
}
