/**
 * Unified schema types with discriminated unions for type-safe field handling.
 *
 * This module provides strongly-typed schema definitions for trigger and action
 * configuration fields, enabling compile-time type checking and runtime type guards.
 */

// ============================================================================
// Conditional Visibility Types
// ============================================================================

/**
 * Operators for conditional visibility expressions
 */
export type VisibilityOperator = 'equals' | 'not_equals' | 'not_empty' | 'empty' | 'in' | 'not_in';

/**
 * Condition for field visibility based on another field's value
 */
export interface VisibilityCondition {
  /** Field name to check */
  field: string;
  /** Comparison operator */
  operator: VisibilityOperator;
  /** Value to compare against (not needed for empty/not_empty) */
  value?: unknown;
}

// ============================================================================
// Repeatable Field Group Types
// ============================================================================

/**
 * Configuration for repeatable field groups
 */
export interface RepeatableConfig {
  /** Minimum number of items */
  min?: number;
  /** Maximum number of items */
  max?: number;
  /** Label for add button */
  add_label?: string;
  /** Label for remove button */
  remove_label?: string;
}

// ============================================================================
// Filter Group Types (for query builders)
// ============================================================================

/**
 * Condition mapping for filter groups - maps property types to available conditions
 */
export type ConditionMapping = Record<string, string[]>;

/**
 * Configuration for filter group fields
 */
export interface FilterGroupConfig {
  /** Field that provides the list of filterable properties */
  property_source?: string;
  /** Endpoint to fetch properties from */
  property_endpoint?: string;
  /** Mapping of property types to available condition operators */
  condition_mappings: ConditionMapping;
  /** Available logical operators (and/or) */
  operators: ('and' | 'or')[];
  /** Maximum nesting depth for filter groups */
  max_depth?: number;
  /** Conditions that don't require a value input */
  value_not_required?: string[];
}

// ============================================================================
// Base Field Type
// ============================================================================

/**
 * Base properties shared by all field types
 */
interface BaseField {
  /** Human-readable field label */
  label: string;
  /** Field description for help text */
  description: string;
  /** Whether the field is required */
  required: boolean;
  /** Display order (lower numbers appear first) */
  order?: number;
  /** Hide from UI (merged into another field) */
  hidden?: boolean;
  /** Conditional visibility - show field only when condition is met */
  visible_when?: VisibilityCondition;
  /** Group this field belongs to */
  group?: string;
  /** Layout width hint: 'full' (default) or '1/2' for half-width side-by-side fields */
  width?: 'full' | '1/2';
}

/**
 * Option for select-type fields
 */
export interface SelectOption {
  value: string;
  label: string;
  description?: string;
  icon?: string;
  disabled?: boolean;
  group?: string;
}

// ============================================================================
// Discriminated Union Field Types
// ============================================================================

/**
 * Simple string input field
 */
export interface StringField extends BaseField {
  type: 'string';
  placeholder?: string;
  default?: string;
}

/**
 * Multi-line text input field
 */
export interface TextField extends BaseField {
  type: 'text';
  placeholder?: string;
  default?: string;
}

/**
 * Numeric input field
 */
export interface NumberField extends BaseField {
  type: 'number';
  placeholder?: string;
  default?: number;
  min?: number;
  max?: number;
}

/**
 * Boolean toggle field
 */
export interface BooleanField extends BaseField {
  type: 'boolean';
  default?: boolean;
}

/**
 * Static select dropdown (options known at build time)
 */
export interface StaticSelectField extends BaseField {
  type: 'select';
  dynamic: false | undefined;
  options: SelectOption[];
  default?: string;
}

/**
 * Dynamic select dropdown (options fetched from API)
 */
export interface DynamicSelectField extends BaseField {
  type: 'select';
  dynamic: true;
  /** REST API endpoint to fetch options from */
  endpoint: string;
  /** Field in API response to use as option value */
  value_field: string;
  /** Field in API response to use as option label */
  label_field: string;
  /** Field that this depends on (e.g., list_id) */
  depends_on?: string;
  default?: string;
}

/**
 * Key-value pairs field (for custom fields/metadata)
 */
export interface KeyValueField extends BaseField {
  type: 'key_value';
  /** If true, fetch key options from endpoint */
  dynamic_options?: boolean;
  /** REST API endpoint for key options */
  endpoint?: string;
  /** Field that this depends on */
  depends_on?: string;
  /** Field in API response to use as key value */
  key_field?: string;
  /** Field in API response to use as key label */
  label_field?: string;
}

/**
 * Repeatable field group - allows adding/removing sets of fields
 */
export interface RepeatableField extends BaseField {
  type: 'repeatable';
  /** Template schema for each item in the repeatable group */
  item_schema: Record<string, SchemaField>;
  /** Repeatable configuration (min, max, labels) */
  repeatable: RepeatableConfig;
  /** Default items */
  default?: Record<string, unknown>[];
}

/**
 * Filter group field - for building query conditions
 */
export interface FilterGroupField extends BaseField {
  type: 'filter_group';
  /** Filter group configuration */
  filter_config: FilterGroupConfig;
}

/**
 * Rich text editor field with formatting toolbar
 */
export interface RichTextField extends BaseField {
  type: 'richtext';
  placeholder?: string;
  default?: string;
}

/**
 * Button group / segmented control field (single selection)
 */
export interface ButtonGroupField extends BaseField {
  type: 'button_group';
  options: SelectOption[];
  default?: string;
}

/**
 * Static multi-select field (options known at build time)
 */
export interface StaticMultiSelectField extends BaseField {
  type: 'multi_select';
  dynamic?: false;
  options: SelectOption[];
  default?: string[];
}

/**
 * Dynamic multi-select field (options fetched from API)
 */
export interface DynamicMultiSelectField extends BaseField {
  type: 'multi_select';
  dynamic: true;
  /** REST API endpoint to fetch options from */
  endpoint: string;
  /** Field in API response to use as option value */
  value_field: string;
  /** Field in API response to use as option label */
  label_field: string;
  /** Field that this depends on */
  depends_on?: string;
  default?: string[];
}

/**
 * Union type for all possible schema field types
 */
export type SchemaField =
  | StringField
  | TextField
  | NumberField
  | BooleanField
  | StaticSelectField
  | DynamicSelectField
  | KeyValueField
  | RepeatableField
  | FilterGroupField
  | RichTextField
  | ButtonGroupField
  | StaticMultiSelectField
  | DynamicMultiSelectField;

/**
 * Schema definition - maps field names to field definitions
 */
export type Schema = Record<string, SchemaField>;

// ============================================================================
// Callback Types
// ============================================================================

/** Callback for field value changes, used by all field components and config panels. */
export type FieldChangeHandler = (fieldName: string, value: unknown) => void;

/** Callback for dynamic option queueing. */
export type QueueFetchHandler = (
  fieldName: string,
  endpoint: string,
  dependsOnValue?: string,
  config?: Record<string, unknown>,
) => void;

// ============================================================================
// Type Guards
// ============================================================================

/**
 * Check if a field has conditional visibility (internal helper)
 */
function hasVisibilityCondition(
  field: SchemaField,
): field is SchemaField & { visible_when: VisibilityCondition } {
  return 'visible_when' in field && field.visible_when !== undefined;
}

/**
 * Evaluate a visibility condition against current form values (internal helper)
 */
function evaluateVisibility(
  condition: VisibilityCondition,
  formValues: Record<string, unknown>,
): boolean {
  const fieldValue = formValues[condition.field];

  switch (condition.operator) {
    case 'equals':
      return fieldValue === condition.value;
    case 'not_equals':
      return fieldValue !== condition.value;
    case 'empty':
      return fieldValue === undefined || fieldValue === null || fieldValue === '';
    case 'not_empty':
      return fieldValue !== undefined && fieldValue !== null && fieldValue !== '';
    case 'in':
      return Array.isArray(condition.value) && condition.value.includes(fieldValue);
    case 'not_in':
      return Array.isArray(condition.value) && !condition.value.includes(fieldValue);
    default:
      return true;
  }
}

/**
 * Check if a field should be visible based on its visibility condition
 */
export function isFieldVisible(field: SchemaField, formValues: Record<string, unknown>): boolean {
  if (!hasVisibilityCondition(field)) {
    return true;
  }
  return evaluateVisibility(field.visible_when, formValues);
}

/**
 * Filter condition value structure
 */
export interface FilterConditionValue {
  property: string;
  property_type?: string;
  condition: string;
  value?: string;
}

/**
 * Filter group value structure
 */
export interface FilterGroupValue {
  operator: 'and' | 'or';
  conditions: FilterConditionValue[];
}
