<?php

if ( !defined( 'ABSPATH' ) ) {
    exit;
}

if ( !class_exists( 'Pricely_Condition_Types' ) ) {

    require_once (dirname( __FILE__ ) . '/condition-types-calendar.php');
    require_once (dirname( __FILE__ ) . '/condition-types-cart.php');
    require_once (dirname( __FILE__ ) . '/condition-types-cart-total.php');
    require_once (dirname( __FILE__ ) . '/condition-types-customer.php');

    class Pricely_Condition_Types {

        private static $instance;
        private $condition_types;

        public static function get_instance(): self {

            if ( !self::$instance ) {

                self::$instance = new self();
            }

            return self::$instance;
        }

        public function validate( $conditions, $data, $items = array() ) {

            if ( !isset( $data[ 'wc' ][ 'context' ] ) ) {

                return false;
            }

            // empty conditions will apply in all cases

            if ( !isset( $conditions[ 'conditions' ] ) ) {

                return true;
            }
            
            if ( class_exists( 'Pricely_Pro_Condition_Types' ) ) {

                $cond_types_obj = Pricely_Pro_Condition_Types::get_instance();

                return $cond_types_obj->validate( $conditions, $data, $items );
            }

            return $this->validate_conditions( $conditions, $data, $items );
        }

        private function validate_conditions( $conditions, $data, $items ) {

            // go through each conditions and validate them
            foreach ( $this->get_conditions( $conditions ) as $condition ) {

                if ( false == $this->validate_condition( $condition, $data, $items ) ) {

                    return false;
                }
            }

            return true;
        }

        private function validate_condition( $condition, $data, $items ) {

            foreach ( $this->load_contidion_types() as $contidion_type ) {

                if ( $contidion_type->can_validate( $condition[ 'condition_type' ], $condition[ 'module_args' ] ) ) {

                    return $contidion_type->validate( $condition, $data, $items );
                }
            }

            return false;
        }

        private function get_conditions( $in_conditions ) {

            $module_args = $this->get_module_args( $in_conditions );

            $conditions = array();

            foreach ( $in_conditions[ 'conditions' ] as $in_condition ) {

                $condition_type = $in_condition[ 'condition_type' ];

                $args_key = 'condition_type_' . $condition_type;

                if ( !isset( $in_condition[ $args_key ] ) ) {

                    continue;
                }

                $conditions[] = $this->prepare_condition_args( $in_condition[ $args_key ], $condition_type, $module_args );
            }

            return $conditions;
        }

        private function prepare_condition_args( $condition_args, $condition_type, $module_args ) {

            $condition = array(
                'condition_type' => $condition_type
            );

            foreach ( $condition_args as $key => $value ) {

                $condition[ $key ] = $value;
            }

            $condition[ 'module_args' ] = $module_args;

            return $condition;
        }

        private function get_module_args( $in_conditions ) {

            $module_args = array(
                'id' => 0,
                'parent_id' => 0,
                'module' => '',
                'context' => '',
            );

            if ( isset( $in_conditions[ 'id' ] ) ) {

                $module_args[ 'id' ] = $in_conditions[ 'id' ];
            }

            if ( isset( $in_conditions[ 'parent_id' ] ) ) {

                $module_args[ 'parent_id' ] = $in_conditions[ 'parent_id' ];
            }

            if ( isset( $in_conditions[ 'module' ] ) ) {

                $module_args[ 'module' ] = $in_conditions[ 'module' ];
            }

            if ( isset( $in_conditions[ 'sub_module' ] ) ) {

                $module_args[ 'sub_module' ] = $in_conditions[ 'sub_module' ];
            }

            if ( isset( $in_conditions[ 'context' ] ) ) {

                $module_args[ 'context' ] = $in_conditions[ 'context' ];
            }

            return $module_args;
        }

        private function load_contidion_types() {

            if ( !is_null( $this->condition_types ) ) {

                return $this->condition_types;
            }

            $this->condition_types = array();

            foreach ( $this->register_contidion_types() as $key => $contidion_type ) {

                if ( !class_exists( $contidion_type ) ) {

                    continue;
                }
                
                if ( !method_exists( $contidion_type, 'can_validate' ) ) {
                  
                    continue;
                }
                
                if ( !method_exists( $contidion_type, 'validate' ) ) {
                  
                    continue;
                }

                if ( method_exists( $contidion_type, 'get_instance' ) ) {

                    $this->condition_types[ $key ] = $contidion_type::get_instance();
                } else {

                    $this->condition_types[ $key ] = new $contidion_type();
                }
            }

            return $this->condition_types;
        }

        private function register_contidion_types() {

            $condition_types = array(
                'calendar' => 'Pricely_Condition_Type_Calendar',
                'cart' => 'Pricely_Condition_Type_Cart',
                'cart_total' => 'Pricely_Condition_Type_Cart_Total',
                'customer' => 'Pricely_Condition_Type_Customer',
            );

            return apply_filters( 'pricely_register_condition_types', $condition_types );
        }

    }

}
