import {
  CheckboxFilterInput,
  CheckboxFilterInputOption,
  FilterInput,
} from '../core';
import { InputType } from '../types';

/**
 * Represents the possible states of a checkbox in a hierarchical structure
 */
export type CheckboxState = 'checked' | 'indeterminate' | 'none';

/**
 * Determines the selection state of a checkbox option within a hierarchical structure.
 * 
 * This helper function calculates whether a checkbox should be displayed as:
 * - 'checked': The option and all its children (if any) are selected
 * - 'indeterminate': The option has children and only some are selected
 * - 'none': The option is not selected
 * 
 * For parent options, the state is determined by their children's selection status.
 * For leaf options, the state is determined by whether the option itself or any of its parent paths are selected.
 * 
 * @param inputs - Array of all filter inputs
 * @param option - The checkbox option to check the state for
 * @returns The current state of the checkbox
 * 
 * @example
 * ```typescript
 * const state = checkboxSelectedHelper(filterInputs, {
 *   path: ['category', 'electronics', 'phones'],
 *   label: 'Phones',
 *   value: 'phones',
 *   values: []
 * });
 * // Returns 'checked' if phones or any parent category is selected
 * ```
 */
export function checkboxSelectedHelper(
  inputs: FilterInput[],
  option: CheckboxFilterInputOption,
): CheckboxState {
  const [group, groupKey, ...optionKeys] = option.path;
  // Find the input that matches the group and key
  const input = inputs.find(
    (input) =>
      input.group === group &&
      input.key === groupKey &&
      input.type === InputType.Checkbox,
  ) as CheckboxFilterInput | undefined;

  // If no input found, return 'none'
  if (!input) {
    return 'none';
  }

  const isParent = Array.isArray(option.values) && option.values.length > 0;
  
  if (isParent) {
    // For parent options, check children selection state
    return getParentCheckboxState(input, optionKeys, option);
  } else {
    // For leaf options, check if this option or any of its parents is selected
    return getLeafCheckboxState(input, optionKeys);
  }
}

/**
 * Calculates the checkbox state for parent options based on their children's selection status.
 * 
 * @param input - The checkbox filter input containing selected paths
 * @param optionKeys - Array of keys representing the path to this option
 * @param option - The parent checkbox option
 * @returns 'checked' if all children are selected, 'indeterminate' if some are selected, 'none' if none are selected
 * @private
 */
function getParentCheckboxState(
  input: CheckboxFilterInput,
  optionKeys: string[],
  option: CheckboxFilterInputOption,
): CheckboxState {
  const currentPath = optionKeys.join('.');
  
  // If the parent itself is selected, it's checked
  if (input.selected?.includes(currentPath)) {
    return 'checked';
  }
  
  // Check how many children are selected (at any level)
  if (input.selected) {
    const selectedChildren = input.selected.filter((selected) =>
      selected.startsWith(currentPath + '.'),
    );
    
    if (selectedChildren.length === 0) {
      return 'none';
    }
    
    // Count all possible children recursively
    const totalChildren = countAllChildren(option);
    
    if (selectedChildren.length === totalChildren) {
      return 'checked';
    } else {
      return 'indeterminate';
    }
  }
  
  return 'none';
}

/**
 * Recursively counts all children (including nested children) of a checkbox option.
 * 
 * @param option - The checkbox option to count children for
 * @returns Total number of child options at all levels
 * @private
 */
function countAllChildren(option: CheckboxFilterInputOption): number {
  if (!option.values || option.values.length === 0) {
    return 0;
  }
  
  let count = option.values.length;
  for (const child of option.values) {
    count += countAllChildren(child);
  }
  
  return count;
}

/**
 * Determines the checkbox state for leaf (non-parent) options.
 * 
 * A leaf option is considered 'checked' if either:
 * - The option itself is directly selected
 * - Any of its parent paths are selected (inherited selection)
 * 
 * @param input - The checkbox filter input containing selected paths
 * @param optionKeys - Array of keys representing the path to this option
 * @returns 'checked' if the option or any parent is selected, 'none' otherwise
 * @private
 */
function getLeafCheckboxState(
  input: CheckboxFilterInput,
  optionKeys: string[],
): CheckboxState {
  if (input.selected) {
    // Check if this option or any of its parents is selected
    for (let i = 1; i <= optionKeys.length; i++) {
      const parentPath = optionKeys.slice(0, i).join('.');
      if (input.selected.includes(parentPath)) {
        return 'checked';
      }
    }
  }
  
  return 'none';
}

/**
 * Legacy helper function that returns a boolean representation of checkbox selection state.
 * 
 * @deprecated Use checkboxSelectedHelper() instead for more accurate state representation
 * @param inputs - Array of all filter inputs
 * @param option - The checkbox option to check
 * @returns true if the checkbox is checked or indeterminate, false if none
 */
export function checkboxSelectedHelperBoolean(
  inputs: FilterInput[],
  option: CheckboxFilterInputOption,
): boolean {
  const state = checkboxSelectedHelper(inputs, option);
  return state === 'checked' || state === 'indeterminate';
}
