import { ConditionalOperator } from 'src/common/enum/conditional-operator.enum';
import { ConditionalCondition } from 'src/common/interfaces/conditional-condition.interface';

/**
 * Evaluates a question's or section's conditional_config against program metadata.
 * Returns true (include) when:
 *   - conditionalConfig is null/undefined/empty (no restriction)
 *   - ALL conditions in the array are satisfied (AND logic)
 *
 * Supported formats:
 * [{ metaKey: 'requiresPayment', operator: 'equals', value: [true] }]
 * [{ field: 'programType', operator: 'in', values: ['HDB', 'MSD'] }]
 */
export function evaluateConditionalConfig(
  conditionalConfig: ConditionalCondition[] | null | undefined,
  programMeta: Record<string, any> = {},
): boolean {
  if (!conditionalConfig || !Array.isArray(conditionalConfig) || conditionalConfig.length === 0) {
    return true;
  }

  return conditionalConfig.every((condition) => evaluateCondition(condition, programMeta));
}

function evaluateCondition(condition: ConditionalCondition, programMeta: Record<string, any>): boolean {
  const key = condition.metaKey ?? condition.field;
  if (!key || !condition.operator) {
    return true;
  }

  const fieldValue = programMeta[key];

  // Support both value (scalar or array) and values (array)
  let values: unknown[];
  if (condition.values !== undefined) {
    values = Array.isArray(condition.values) ? condition.values : [condition.values];
  } else if (condition.value !== undefined) {
    values = Array.isArray(condition.value) ? condition.value : [condition.value];
  } else {
    values = [];
  }

  switch (condition.operator) {
    case ConditionalOperator.IN:
      return values.includes(fieldValue);
    case ConditionalOperator.NOT_IN:
      return !values.includes(fieldValue);
    case ConditionalOperator.EQUALS:
      return fieldValue === values[0];
    case ConditionalOperator.NOT_EQUALS:
      return fieldValue !== values[0];
    case ConditionalOperator.GREATER_THAN:
      return (fieldValue as number) > (values[0] as number);
    case ConditionalOperator.GREATER_THAN_OR_EQUAL:
      return (fieldValue as number) >= (values[0] as number);
    case ConditionalOperator.LESS_THAN:
      return (fieldValue as number) < (values[0] as number);
    case ConditionalOperator.LESS_THAN_OR_EQUAL:
      return (fieldValue as number) <= (values[0] as number);
    default:
      return true;
  }
}
