<?php

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


if (!class_exists('WooPricely_Product_Prices')) {

    class WooPricely_Product_Prices {

        private static $products = array();
        private static $calculating = false;

        public static function get_product_regular_price($price, $src_product) {
            if (is_admin()) {
                return $price;
            }
            if (self::$calculating == true) {
                return $price;
            }

            $product = WooPricely::create_product_identifier($src_product);
            self::$calculating = true;
            $product = self::calculate_product_prices($product);
            self::$calculating = false;

            if (isset($product['calc_regular_price']) && $product['type'] != 'variable') {
                return $product['calc_regular_price'];
            }

            return $price;
        }

        public static function get_product_sale_price($price, $src_product) {
            if (is_admin()) {
                return $price;
            }
            if (self::$calculating == true) {
                return $price;
            }

            $product = WooPricely::create_product_identifier($src_product);
            self::$calculating = true;
            $product = self::calculate_product_prices($product);

            self::$calculating = false;

            if (isset($product['calc_sale_price']) && $product['type'] != 'variable') {
//                if (self::is_cart_or_checkout()) {
//                    return WooPricely_Checkout_Prices::get_product_sale_price($product['calc_sale_price'], $product);
//                }
                return $product['calc_sale_price'];
            }

            return $price;
        }

        public static function get_is_purchasable($is_purchasable, $src_product) {
            if (is_admin()) {
                return $is_purchasable;
            }
            if (self::$calculating == true) {
                return $is_purchasable;
            }

            self::$calculating = true;
            $product = self::calculate_product_prices(WooPricely::create_product_identifier($src_product));
            self::$calculating = false;
            if (isset($product['calc_sale_price']) || isset($product['calc_regular_price'])) {

                return true;
            }
            return $is_purchasable;
        }

        public static function get_is_on_sale($is_on_sale, $src_product) {
            if (is_admin()) {
                return $is_on_sale;
            }
            if (self::$calculating == true) {
                return $is_on_sale;
            }

            self::$calculating = true;
            $product = self::calculate_product_prices(WooPricely::create_product_identifier($src_product));
            self::$calculating = false;

            if (count($product) == 0) {
                return $is_on_sale;
            }
            $regular_price = 0;
            $sale_price = 0;

            if ($product['type'] == 'variable') {
                $is_variables_on_sale = false;
                foreach (self::$products as $prod) {

                    if ($prod['id'] == $product['id']) {
                        if (isset($prod['regular_price']) && $prod['regular_price'] != '') {
                            $regular_price = $prod['regular_price'];
                        }
                        if (isset($prod['sale_price']) && $prod['sale_price'] != '') {
                            $sale_price = $prod['sale_price'];
                        }
                        if (isset($prod['calc_regular_price']) && $prod['calc_regular_price'] != '') {
                            $regular_price = $prod['calc_regular_price'];
                        }
                        if (isset($prod['calc_sale_price']) && $prod['calc_sale_price'] != '') {
                            $sale_price = $prod['calc_sale_price'];
                        }
                        $is_variables_on_sale = ($regular_price > $sale_price);
                        if ($is_variables_on_sale == true) {
                            return true;
                        }
                    }
                }
            }

            if (isset($product['regular_price']) && $product['regular_price'] != '') {
                $regular_price = $product['regular_price'];
            }
            if (isset($product['sale_price']) && $product['sale_price'] != '') {
                $sale_price = $product['sale_price'];
            }
            if (isset($product['calc_regular_price']) && $product['calc_regular_price'] != '') {
                $regular_price = $product['calc_regular_price'];
            }
            if (isset($product['calc_sale_price']) && $product['calc_sale_price'] != '') {
                $sale_price = $product['calc_sale_price'];
            }
            return ($regular_price > $sale_price);
        }

        public static function get_on_sale_products($query_args, $attributes = array(), $type = '') {
            if (is_admin()) {
                return $query_args;
            }
            if (count($attributes) == 0) {
                return $query_args;
            }

            if ($type != 'sale_products') {
                return $query_args;
            }
           

            global $zc_pri;


            if (!isset($zc_pri['on_sale_products']['enable']) || $zc_pri['on_sale_products']['enable'] == 'no') {
                return $query_args;
            }

            $product_count = isset($zc_pri['on_sale_products']['product_count']) ? $zc_pri['on_sale_products']['product_count'] : 15;
            $replace_default = isset($zc_pri['on_sale_products']['replace_default']) ? $zc_pri['on_sale_products']['replace_default'] : 'no';

            $product_ids = array();
            if ($replace_default == 'no') {
                if (isset($query_args['post__in']) && is_array($query_args['post__in'])) {
                    foreach ($query_args['post__in'] as $p_id) {
                        $product_ids[$p_id] = $p_id;
                    }
                }
            }

            $args = array(
                'post_type' => 'product',
                'fields' => 'ids',
                'posts_per_page' => $product_count
            );
            $db_products = get_posts($args);


            if (!isset($attributes['limit'])) {
                $attributes['limit'] = $product_count;
            }

            $short_count = $attributes['limit'];

            foreach ($db_products as $prod_id) {
                if (count($product_ids) >= $short_count) {
                    break;
                }
                $prod = wc_get_product($prod_id);

                if (self::get_is_on_sale(false, $prod)) {
                    $product_ids[$prod_id] = $prod_id;
                }
            }

            $query_args['post__in'] = array_values($product_ids);
            return $query_args;
        }

        public static function get_product_price($price, $src_product) {
            return self::get_product_sale_price($price, $src_product);
        }

        public static function get_product_date_on_sale_from($on_sale_from, $src_product) {
            if (is_admin()) {
                return $on_sale_from;
            }
            if (self::$calculating == true) {
                return $on_sale_from;
            }

            self::$calculating = true;
            $product = self::calculate_product_prices(WooPricely::create_product_identifier($src_product));
            self::$calculating = false;
            if (isset($product['schedule_sale_from']) && $product['schedule_sale_from'] != '') {
                return get_the_time('Y-m-d', $product['schedule_sale_from']);
            }

            return $on_sale_from;
        }

        public static function get_product_date_on_sale_to($on_sale_to, $src_product) {
            if (is_admin()) {
                return $on_sale_to;
            }
            if (self::$calculating == true) {
                return $on_sale_to;
            }

            self::$calculating = true;
            $product = self::calculate_product_prices(WooPricely::create_product_identifier($src_product));
            self::$calculating = false;
            if (isset($product['schedule_sale_to']) && $product['schedule_sale_to'] != '') {
                return get_the_time('Y-m-d', $product['schedule_sale_to']);
            }

            return $on_sale_to;
        }

        public static function get_product_promo_message($product_id) {

            if (is_admin()) {
                return '';
            }
            if (self::$calculating == true) {
                return '';
            }

            self::$calculating = true;
            $src_product = wc_get_product($product_id);
            $product = self::calculate_product_prices(WooPricely::create_product_identifier($src_product));
            self::$calculating = false;
            if (isset($product['promo_message'])) {
                return $product['promo_message'];
            }

            return '';
        }

        public static function get_prices_time_left($product_id) {

            if (is_admin()) {
                return '';
            }
            if (self::$calculating == true) {
                return '';
            }

            self::$calculating = true;
            $src_product = wc_get_product($product_id);
            $product = self::calculate_product_prices(WooPricely::create_product_identifier($src_product));
            self::$calculating = false;
            if (isset($product['time_left'])) {
                return $product['time_left'];
            }

            return '';
        }

        public static function get_calculated_product_prices($key) {
            if (!isset(self::$products[$key])) {
                return array();
            }
            return self::$products[$key];
        }

        private static function calculate_product_prices($product) {

            global $zc_pri;
            $rls_mode = isset($zc_pri['products_pricing']['mode']) ? $zc_pri['products_pricing']['mode'] : 'all';
            $max_discount_amount = isset($zc_pri['products_pricing']['max_discount_amount']) ? $zc_pri['products_pricing']['max_discount_amount'] : 0;
            $max_discount_type = isset($zc_pri['products_pricing']['max_discount_type']) ? $zc_pri['products_pricing']['max_discount_type'] : 'no';



            if ($rls_mode == 'no') {
                return array();
            }

            // Return cached product prices
            if (isset(self::$products[$product['key']])) {
                return self::$products[$product['key']];
            }


            $rules = self::get_product_price_valid_rules($product);

            if (count($rules) == 0) {
                return array();
            }

            //Get product source prices
            $product['regular_price'] = self::get_src_regular_price($product);
            $product['sale_price'] = self::get_src_sale_price($product);


            // Calculate Products prices by each pricing rule
            foreach ($rules as $rule) {

                //Calculate product regular price
                if ($rule['price_mode'] == 'regular_price' || $rule['price_mode'] == 'regular_sale_price') {
                    $reg_adj = $rule['regular_adj']['adjustment'];
                    $reg_base_on = $rule['regular_adj']['base_on'];
                    $reg_amount = $rule['regular_adj']['amount'];

                    $reg_price = self::get_calc_price($product, $reg_adj, $reg_base_on, $reg_amount, $max_discount_type, $max_discount_amount);


                    //Adjust bigger or smaller regular price

                    $old_price = $reg_price;
                    if (isset($product['calc_regular_price'])) {
                        $old_price = $product['calc_regular_price'];
                    }
                    $product['calc_regular_price'] = self:: get_bigger_or_smaller_price($rls_mode, $old_price, $reg_price);
                }

                if ($rule['price_mode'] == 'regular_price' && isset($rule['clear_sale_price']) && $rule['clear_sale_price'] == 'yes') {

                    $product['calc_sale_price'] = $product['calc_regular_price'];
                }

                if (isset($product['calc_regular_price']) && $product['sale_price'] == '') {
                    $product['calc_sale_price'] = $product['calc_regular_price'];
                }

                //Calculate product sale price
                if ($rule['price_mode'] == 'sale_price' || $rule['price_mode'] == 'regular_sale_price') {
                    $sal_adj = $rule['sale_adj']['adjustment'];
                    $sal_base_on = $rule['sale_adj']['base_on'];
                    $sal_amount = $rule['sale_adj']['amount'];
                    if (!isset($product['calc_regular_price'])) {
                        $product['calc_regular_price'] = $product['regular_price'];
                    }

                    $sale_price = self::get_calc_price($product, $sal_adj, $sal_base_on, $sal_amount, $max_discount_type, $max_discount_amount);



                    //Adjust bigger or smaller sale price
                    $old_price = $sale_price;
                    if (isset($product['calc_sale_price'])) {
                        $old_price = $product['calc_sale_price'];
                    }
                    $product['calc_sale_price'] = self:: get_bigger_or_smaller_price($rls_mode, $old_price, $sale_price);


                    if ($rule['schedule_sale']['enable'] == 'yes') {
                        $product['schedule_sale_from'] = $rule['schedule_sale']['from'];
                        $product['schedule_sale_to'] = $rule['schedule_sale']['to'];
                    }
                }

                if ($rule['message'] != '') {
                    $product['promo_message'] = $rule['message'];
                }

                if (isset($rule['time_left'])) {
                    $product['time_left'] = $rule['time_left'];
                }
            }

            //Cache product prices            
            self::$products[$product['key']] = $product;

            return $product;
        }

        private static function get_product_price_valid_rules($product) {
            global $zc_pri;
            $valid_rules = array();


            if (!isset($zc_pri['products_pricing_rules'])) {
                return $valid_rules;
            }

            // validate rules
            foreach ($zc_pri['products_pricing_rules'] as $rule) {
                if ($rule['enable'] == 'yes') {


                    $products = self::validate_product_price_rule($rule, $product);


                    if (count($products) > 0) {
                        $rl = array(
                            'apply_mode' => $rule['apply_mode'],
                            'price_mode' => $rule['price_mode'],
                            'admin_note' => $rule['admin_note'],
                            'message' => $rule['message'],
                        );
                        if (WooPricely_CountDown::is_datetime_set() == true) {
                            $rl['time_left'] = WooPricely_CountDown::get_datetime();
                        }
                        if (isset($rule['clear_sale_price'])) {
                            $rl['clear_sale_price'] = $rule['clear_sale_price'];
                        }
                        if (isset($rule['regular_adj'])) {
                            $rl['regular_adj'] = $rule['regular_adj'];
                        }

                        if (isset($rule['sale_adj'])) {
                            $rl['sale_adj'] = $rule['sale_adj'];
                        }

                        if (isset($rule['schedule_sale'])) {
                            $rl['schedule_sale'] = $rule['schedule_sale'];
                        }


                        if ($rule['apply_mode'] == 'only_this') {
                            $valid_rules = array();
                            $valid_rules[] = $rl;
                            break;
                        }
                        $valid_rules[] = $rl;
                    }
                }
            }

            //Remove unwanted rules
            $valid_rls = $valid_rules;
            $valid_rules = array();
            for ($i = 0; $i < count($valid_rls); $i++) {
                if ($valid_rls[$i]['apply_mode'] == 'if_others' && count($valid_rls) == 1) {
                    continue;
                }
                if ($valid_rls[$i]['apply_mode'] == 'if_no_others' && count($valid_rls) > 1) {
                    continue;
                }
                $valid_rules[] = $valid_rls[$i];
            }


            $rls_mode = isset($zc_pri['products_pricing']['mode']) ? $zc_pri['products_pricing']['mode'] : 'all';

            if ($rls_mode == 'first' && count($valid_rules) > 1) {
                $first_rule = $valid_rules[0];
                $valid_rules = array();
                $valid_rules[] = $first_rule;
            }

            if ($rls_mode == 'last' && count($valid_rules) > 1) {
                $last_rule = $valid_rules[(count($valid_rules) - 1)];
                $valid_rules = array();
                $valid_rules[] = $last_rule;
            }
            return $valid_rules;
        }

        private static function validate_product_price_rule($rule, $product) {
            $valid_products = array($product);
            $is_valid = true;

            $rule_args = array(
                'section' => 'product_prices',
                'panel' => 'products',
            );
            if (isset($rule['products'])) {
                $valid_products = WooPricely::validate_products($rule['products'], $valid_products, $rule_args);
            }
            WooPricely_CountDown::clear_datetime();
            if (isset($rule['conditions'])) {
                $rule_args['panel'] = 'conditions';
                $is_valid = WooPricely::validate_conditions($rule['conditions'], $rule_args);
            }
            if (count($valid_products) > 0 && $is_valid == true) {
                return $valid_products;
            }
            return array();
        }

        private static function is_cart_or_checkout() {


            if (defined('WOOCOMMERCE_CART') || defined('WOOCOMMERCE_CHECKOUT')) {
                return true;
            }
            return false;
        }

        private static function get_calc_price($product, $adjustment, $base_on, $amount, $max_discount_type, $max_discount_amount) {


            if (!is_numeric($amount)) {
                $amount = 0;
            }

            $price = self::get_base_on($product, $base_on);


            $new_price = $amount;

            if (!is_numeric($price) && $adjustment != 'fixed_price') {
                $new_price = $price;
            } else if (is_numeric($price)) {
                // Calculate percentage amount
                if ($adjustment == 'per_discount' || $adjustment == 'per_fee') {
                    $amount = ($amount / 100) * $price;
                }

                // Adjust discount amount to maximun if needed
                if ($amount > $max_discount_amount && is_numeric($max_discount_amount)) {
                    if ($max_discount_type == 'per') {

                        $amount = $max_discount_amount;
                    } else if ($max_discount_type == 'amount') {
                        $amount = $max_discount_amount;
                    }
                }

                // Adjust new price from discount amount
                if ($adjustment == 'fixed_discount' || $adjustment == 'per_discount') {
                    $new_price = $price - $amount;
                }

                if ($adjustment == 'fixed_fee' || $adjustment == 'per_fee') {
                    $new_price = $price + $amount;
                }
            }







            if ($new_price < 0) {
                return 0;
            }
            return $new_price;
        }

        private static function get_base_on($product, $base_on) {
            $b_price = $product['regular_price'];

            if ($base_on == 'sale_price' && is_numeric($product['sale_price'])) {
                $b_price = $product['sale_price'];
            } else if ($base_on == 'calc_reg_price' && isset($product['calc_regular_price'])) {

                $b_price = $product['calc_regular_price'];
            } else if ($base_on == 'calc_sale_price') {
                if (isset($product['calc_sale_price']) && is_numeric($product['calc_sale_price'])) {
                    $b_price = $product['calc_sale_price'];
                } else if (is_numeric($product['sale_price'])) {
                    $b_price = $product['sale_price'];
                }
            }

            return $b_price;
        }

        private static function get_src_regular_price($product) {
            try {

                if (isset($product['variation_id'])) {
                    return wc_get_product($product['variation_id'])->get_regular_price(false);
                } else {
                    return wc_get_product($product['id'])->get_regular_price(false);
                }
            } catch (Exception $ex) {
                
            }
            return '';
        }

        private static function get_src_sale_price($product) {
            try {

                if (isset($product['variation_id'])) {
                    return wc_get_product($product['variation_id'])->get_sale_price(false);
                } else {
                    return wc_get_product($product['id'])->get_sale_price(false);
                }
            } catch (Exception $ex) {
                
            }
            return '';
        }

        private static function get_bigger_or_smaller_price($bigger_or_smaller, $old_price, $new_price) {
            $the_price = $new_price;
            if ($bigger_or_smaller == 'bigger' && $old_price < $new_price) {
                $the_price = $old_price;
            } else if ($bigger_or_smaller == 'bigger') {
                $the_price = $new_price;
            }
            if ($bigger_or_smaller == 'smaller' && $old_price < $new_price) {
                $the_price = $new_price;
            } else if ($bigger_or_smaller == 'smaller') {
                $the_price = $old_price;
            }

            return $the_price;
        }

    }

}