<?php
if ( ! defined( 'ABSPATH' ) ) { exit; }

/**
 * Validator Registry - Extensible validation system
 * 
 * Allows plugins/themes to register custom validation rules that automatically
 * apply to both UI saves and import operations.
 */
class KNSDD_Validator_Registry {

    /**
     * Registered validators
     * @var array
     */
    private static $validators = [];

    /**
     * Initialize the registry and register core validators
     */
    public static function init() {
        // Register core validators
        self::register_core_validators();
        
        // Allow plugins/themes to register custom validators
        do_action( 'knsdd_register_validators' );
    }

    /**
     * Register a validation rule
     *
     * @param string $id Unique validator ID
     * @param array $args Validator configuration
     */
    public static function register( $id, $args ) {
        $defaults = [
            'callback' => null,
            'priority' => 10,
            'context' => ['ui', 'import'], // Where to apply: ui, import, or both
            'type' => 'intra_group', // intra_group, cross_group, or custom
            'description' => '',
            'enabled' => true
        ];
        
        $validator = wp_parse_args( $args, $defaults );
        
        if ( ! is_callable( $validator['callback'] ) ) {
            return false;
        }
        
        self::$validators[ $id ] = $validator;
        return true;
    }

    /**
     * Unregister a validation rule
     *
     * @param string $id Validator ID
     */
    public static function unregister( $id ) {
        unset( self::$validators[ $id ] );
    }

    /**
     * Get all registered validators for a specific context
     *
     * @param string $context 'ui' or 'import'
     * @param string $type Optional type filter
     * @return array
     */
    public static function get_validators( $context = 'all', $type = 'all' ) {
        $validators = [];
        
        foreach ( self::$validators as $id => $validator ) {
            if ( ! $validator['enabled'] ) {
                continue;
            }
            
            if ( $context !== 'all' && ! in_array( $context, $validator['context'] ) ) {
                continue;
            }
            
            if ( $type !== 'all' && $validator['type'] !== $type ) {
                continue;
            }
            
            $validators[ $id ] = $validator;
        }
        
        // Sort by priority
        uasort( $validators, function( $a, $b ) {
            return $a['priority'] - $b['priority'];
        });
        
        return $validators;
    }

    /**
     * Run intra-group validators
     *
     * @param array $rules Sanitized rules
     * @param string $context 'ui' or 'import'
     * @param array $extra_data Additional context data
     * @return array Validation result
     */
    public static function validate_intra_group( $rules, $context = 'ui', $extra_data = [] ) {
        $validators = self::get_validators( $context, 'intra_group' );
        $errors = [];
        $warnings = [];
        $sets = [[], [], []]; // Default empty sets
        
        foreach ( $validators as $id => $validator ) {
            $result = call_user_func( $validator['callback'], $rules, $context, $extra_data );
            
            if ( is_array( $result ) ) {
                if ( isset( $result['errors'] ) && is_array( $result['errors'] ) ) {
                    $errors = array_merge( $errors, $result['errors'] );
                }
                if ( isset( $result['warnings'] ) && is_array( $result['warnings'] ) ) {
                    $warnings = array_merge( $warnings, $result['warnings'] );
                }
                if ( isset( $result['sets'] ) && is_array( $result['sets'] ) ) {
                    $sets = $result['sets']; // Use the last valid sets
                }
                
                // If this validator failed critically, stop processing
                if ( isset( $result['stop'] ) && $result['stop'] === true ) {
                    break;
                }
            }
        }
        
        return [
            'ok' => empty( $errors ),
            'errors' => $errors,
            'warnings' => $warnings,
            'sets' => $sets
        ];
    }

    /**
     * Run cross-group validators
     *
     * @param string $group Group name
     * @param string $start Start date
     * @param string $end End date
     * @param array $my_sets Rule sets from build_sets_from_rules
     * @param array $my_rules Current group's rules
     * @param array $dataset Dataset for validation
     * @param string $context 'ui' or 'import'
     * @param array $extra_data Additional context data
     * @return array Validation result
     */
    public static function validate_cross_group( $group, $start, $end, $my_sets, $my_rules, $dataset, $context = 'ui', $extra_data = [] ) {
        $validators = self::get_validators( $context, 'cross_group' );
        
        foreach ( $validators as $id => $validator ) {
            $result = call_user_func( $validator['callback'], $group, $start, $end, $my_sets, $my_rules, $dataset, $context, $extra_data );
            
            if ( is_array( $result ) && isset( $result['conflict'] ) && $result['conflict'] ) {
                return $result; // Return first conflict found
            }
        }
        
        return [ 'conflict' => false, 'with' => '' ];
    }

    /**
     * Run custom validators
     *
     * @param mixed $data Data to validate
     * @param string $context 'ui' or 'import'
     * @param array $extra_data Additional context data
     * @return array Validation results
     */
    public static function validate_custom( $data, $context = 'ui', $extra_data = [] ) {
        $validators = self::get_validators( $context, 'custom' );
        $results = [];
        
        foreach ( $validators as $id => $validator ) {
            $result = call_user_func( $validator['callback'], $data, $context, $extra_data );
            $results[ $id ] = $result;
        }
        
        return $results;
    }

    /**
     * Register core validation rules
     */
    private static function register_core_validators() {
        // Core intra-group validator (existing KNSDD_Rules_Validator logic)
        self::register( 'core_intra_group', [
            'callback' => [ 'KNSDD_Rules_Validator', 'validate_intra_group' ],
            'priority' => 5,
            'context' => ['ui', 'import'],
            'type' => 'intra_group',
            'description' => 'Core intra-group conflict validation (range overlaps, duplicate scopes)'
        ]);
        
        // Core cross-group validator (existing KNSDD_Conflicts logic)
        self::register( 'core_cross_group', [
            'callback' => [ __CLASS__, 'core_cross_group_validator' ],
            'priority' => 5,
            'context' => ['ui', 'import'],
            'type' => 'cross_group',
            'description' => 'Core cross-group conflict validation (date/scope/customer overlaps)'
        ]);
    }

    /**
     * Core cross-group validator wrapper
     */
    public static function core_cross_group_validator( $group, $start, $end, $my_sets, $my_rules, $dataset, $context, $extra_data ) {
        if ( $context === 'import' ) {
            // Use dataset-aware version for import
            return KNSDD_Conflicts::check_cross_group_conflict_dataset( $group, $start, $end, $my_sets, $my_rules, $dataset );
        } else {
            // Use regular version for UI - preload all group data for performance
            $all_groups = KNSDD_Data::get_groups();
            $preloaded_data = [ 'dates' => [], 'rules' => [] ];
            
            foreach ( $all_groups as $g ) {
                $preloaded_data['dates'][$g] = KNSDD_Data::get_dates_for_group( $g );
                $preloaded_data['rules'][$g] = KNSDD_Data::get_rules_for_group( $g );
            }
            
            return KNSDD_Conflicts::check_cross_group_conflict( $group, $start, $end, $my_sets, $preloaded_data );
        }
    }

    /**
     * Get validator info for debugging/admin
     *
     * @return array
     */
    public static function get_registry_info() {
        return [
            'total_validators' => count( self::$validators ),
            'enabled_validators' => count( array_filter( self::$validators, function( $v ) { return $v['enabled']; } ) ),
            'validators' => self::$validators
        ];
    }

    /**
     * Enable/disable a validator
     *
     * @param string $id Validator ID
     * @param bool $enabled Enable or disable
     */
    public static function set_validator_enabled( $id, $enabled ) {
        if ( isset( self::$validators[ $id ] ) ) {
            self::$validators[ $id ]['enabled'] = (bool) $enabled;
        }
    }
}
