<?php

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

if (!class_exists('WooPricely_Checkout_Group_Prices')) {

    class WooPricely_Checkout_Group_Prices {

        public static function init() {
            add_filter('zcpri/process-checkout-prices-products_group-rule', array(new self(), 'process_rule'), 1, 3);
            add_filter('zcpri/get-checkout-prices-products_group-product-data', array(new self(), 'get_products_data'), 1, 2);
            add_filter('zcpri/get-checkout-prices-products_group-discounts', array(new self(), 'calc_products_prices'), 1, 2);
        }

        public static function process_rule($rule, $raw_rule, $product_id) {
            $rule['qty_base_on'] = $raw_rule['qty_base_on'];
            $rule['group_discount'] = $raw_rule['group_discount'];
            $rule['products_in_group'] = $raw_rule['products_in_group'];
            if (isset($raw_rule['group_product_rules'])) {
                $rule['group_product_rules'] = $raw_rule['group_product_rules'];
            }
            $rule['grouped_products'] = self::get_checkout_products($raw_rule, $product_id);
            return $rule;
        }

        public static function calc_products_prices($r_products, $rule) {
            $in_group = 0;
            if (isset($rule['products_in_group'])) {
                $in_group = count($rule['products_in_group']);
            }

            $discounts_total = 0;

            foreach (self::get_group_quantities($rule['grouped_products'], $rule['qty_base_on']) as $products_group) {
                if ($in_group > 0) {
                    $prods = self::get_group_discount($products_group, $rule['group_discount'], $in_group);
                    foreach ($prods['products'] as $key => $prod) {
                        $r_products['products'][$key]['key'] = $prod['key'];
                        $r_products['products'][$key]['qty'] = $prod['quantity'];
                        $r_products['products'][$key]['cart_key'] = $prod['cart_key'];
                        $r_products['products'][$key]['cart_price'] = $prod['cart_price'];
                        $r_products['products'][$key]['discount_price'] = $prod['discount_price'];
                        $r_products['products'][$key]['discount_detail'] = $prod['discount_detail'];
                        $r_products['products'][$key]['mode'] = $rule['mode'];
                    }
                    $discounts_total += $prods['discounts_total'];
                    if (isset($prods['stop_loop']) && $prods['stop_loop'] == 'yes') {
                        break;
                    }
                }
            }


            $r_products['discounts_total'] = $discounts_total;


            return $r_products;
        }

        public static function get_products_data($r_data, $rule) {
            if (isset($rule['grouped_products'])) {
                foreach (self::merge_grouped_products($rule['grouped_products']) as $key => $product) {
                    $r_dat = array(
                        'id' => $product['id'],
                        'message' => $rule['message'],
                        'mode' => $rule['mode'],
                    );
                    if (isset($rule['time_left'])) {
                        $r_dat['time_left'] = $rule['time_left'];
                    }
                    $r_data[] = $r_dat;
                }
            }

            return $r_data;
        }

        private static function get_checkout_products($rule, $product_id) {
            $products = array();
            if (!isset($rule['products_in_group'])) {
                return $products;
            }
            foreach ($rule['products_in_group'] as $p_filters) {
                $products_filters = array();

                if (isset($rule['group_product_rules'])) {
                    foreach ($rule['group_product_rules'] as $g_filters) {
                        $products_filters[] = $g_filters;
                    }
                }

                $pr_filters['rule_type'] = $p_filters['rule_type'];

                $pr_filters['rule_type_' . $p_filters['rule_type']] = $p_filters['rule_type_' . $p_filters['rule_type']];
                $pr_filters['rule_type_' . $p_filters['rule_type']]['is_req'] = 'yes';

                $products_filters[] = $pr_filters;

                $products[] = array(
                    'qty' => $p_filters['qty'],
                    'group' => self::get_group_products($products_filters, $product_id)
                );
            }

            return $products;
        }

        private static function get_group_products($products_filters, $product_id) {
            if ($product_id > 0) {
                $valid_products = array();
                $product = WooPricely::create_product_identifier(wc_get_product($product_id));
                if (isset($product['key'])) {
                    $valid_products[$product['key']] = $product;
                }
            } else {
                $valid_products = WooPricely::get_products_from_cart();
            }
            $is_valid = true;


            $rule_args = array(
                'section' => 'checkout_prices',
                'panel' => 'products',
                'is_single' => false,
            );

            if ($product_id > 0) {
                $rule_args['is_single'] = true;
                $rule_args['product_id'] = $product_id;
            }

            if (count($products_filters) > 0) {
                $valid_products = WooPricely::validate_products($products_filters, $valid_products, $rule_args);
            } else {
                return array();
            }
            return $valid_products;
        }

        private static function get_group_discount($grouped_products, $group_discount, $in_group) {
            $products = array(
                'products' => array(),
                'discounts_total' => 0
            );


            if (count($grouped_products) < $in_group) {
                return $products;
            }


            $rep_count = 0;

            foreach ($grouped_products as $g_products) {
                $r_count = self::get_group_part_repeat_count($g_products);
                if ($r_count == 0) {
                    return $products;
                }
                if ($r_count < $rep_count || $rep_count == 0) {
                    $rep_count = $r_count;
                }
            }


            if ($rep_count > 1 && $group_discount['repeat'] != 'yes') {
                $rep_count = 1;
            }
            if ($rep_count == 0) {
                return $products;
            }

            $total_qty = 0;
            $total_price = 0;

            $discounts_total = 0;

            $all_qty = self::get_all_group_count($grouped_products, $rep_count);

            foreach ($grouped_products as $g_products) {
                $d_count = 0;
                if ($g_products['qty'] == '') {
                    return $products;
                }



                foreach ($g_products['group'] as $gg_products) {
                    foreach ($gg_products['products'] as $key => $product) {
                        $p_qty = 0;
                        for ($i = 0; $i < $product['quantity']; $i++) {
                            if ($d_count < ($g_products['qty'] * $rep_count)) {
                                $p_qty++;
                                $d_count++;
                            }
                        }



                        if ($p_qty > 0) {
                            if ($group_discount['discount_type'] == 'fixed_group_price' || $group_discount['discount_type'] == 'fixed_group_discount') {
                                $total_qty += $p_qty;
                                $total_price += self::get_product_price($product, $group_discount['base_on'], $p_qty);
                            } else {
                                $calc_price = self::calc_products_discount($product, $group_discount, $all_qty);

                                $d_price = (($calc_price * $p_qty) + ($product['cart_price'] * ($product['quantity'] - $p_qty))) / $product['quantity'];

                                $products['products'][$key] = $product;
                                $products['products'][$key]['discount_price'] = $d_price;
                                $products['products'][$key]['discount_detail'][] = array('qty' => $p_qty, 'price' => $calc_price);
                                $discounts_total += ($products['products'][$key]['cart_price'] - $d_price) * $products['products'][$key]['quantity'];
                            }
                        }
                    }
                }
            }



            if ($group_discount['discount_type'] == 'fixed_group_price' || $group_discount['discount_type'] == 'fixed_group_discount') {

                if ($group_discount['amount'] == '') {
                    $group_discount['amount'] = 0;
                }
                $amount = $group_discount['amount'];
                if ($group_discount['discount_type'] == 'fixed_group_discount') {
                    $amount = $total_price - $group_discount['amount'];
                }

                if ($rep_count > 1) {
                    $amount = $amount * $rep_count;
                }

                $s_calc_price = round($amount / $total_qty, wc_get_price_decimals());
                $prices = array();

                $prices_total = 0;
                for ($i = 0; $i < $total_qty; $i++) {
                    $prices[] = $s_calc_price;
                    $prices_total += $s_calc_price;
                }

                if ($prices_total <> $amount && count($prices) > 0) {
                    $prices[count($prices) - 1] += $amount - $prices_total;
                }
//                sort($prices);
//                $prices = array_reverse($prices);


                $prices_pointer = 0;
                foreach ($grouped_products as $g_products) {
                    $g_qty = $g_products['qty'] * $rep_count;

                    foreach ($g_products['group'] as $gg_products) {
                        foreach ($gg_products['products'] as $key => $product) {

                            if ($total_qty <= 0) {
                                break;
                            }
                            $products['products'][$key] = $product;
                            $prod_qty = $products['products'][$key]['quantity'];

                            $calc_price = 0;


                            $p_prices = array();
                            $last_p_prices = 0;
                            for ($i = 0; $i < $g_qty; $i++) {
                                $p_prices[] = $prices[$prices_pointer];
                                $calc_price += $prices[$prices_pointer];
                                $last_p_prices = $prices[$prices_pointer];
                                $prices_pointer++;
                            }


                            $calc_price = $calc_price / count($p_prices);



                            if ($calc_price < 0) {
                                $calc_price = 0;
                            }


                            if ($g_qty >= $prod_qty) {
                                $products['products'][$key]['id'] = $product['id'];
                                $products['products'][$key]['discount_price'] = $calc_price;
                                $products['products'][$key]['discount_detail'] = self::get_group_prices_details($p_prices);
                            } else {
                                $d_price = (($calc_price * $g_qty) + ($product['cart_price'] * ($product['quantity'] - $g_qty))) / $product['quantity'];
                                $products['products'][$key]['id'] = $product['id'];
                                $products['products'][$key]['discount_price'] = $d_price;
                                $d_qty = $prod_qty - $g_qty;
                                $products['products'][$key]['discount_detail'] = self::get_group_prices_details($p_prices);
                            }


                            $discounts_total += (($products['products'][$key]['cart_price'] * $products['products'][$key]['quantity']) - ($products['products'][$key]['discount_price'] * $products['products'][$key]['quantity']));

                            $total_qty -= $g_qty;
                        }
                    }
                }
            }

            if ($group_discount['repeat'] != 'yes' && $discounts_total > 0) {
                $products['stop_loop'] = 'yes';
            }
            $products['discounts_total'] = $discounts_total;

            return $products;
        }

        private static function calc_products_discount($product, $discount_opt, $qty) {
            if ($discount_opt['discount_type'] == 'free') {
                return 0;
            }

            $disc_price = 0;
            if (is_numeric($discount_opt['amount'])) {
                $disc_price = $discount_opt['amount'];
            }


            if ($discount_opt['discount_type'] == 'fixed_price_unit' || $discount_opt['discount_type'] == '') {
                return round($disc_price, wc_get_price_decimals());
            }

            if ($discount_opt['discount_type'] == 'fixed_group_price') {
                return round($disc_price / $qty, wc_get_price_decimals());
            }




            $item_price = $product['cart_price'];

            $base_on = $discount_opt['base_on'];

            if ($base_on != '' && $base_on != 'cart_price') {
                $src_price = WooPricely::get_product_price($product['key'], $base_on);
                if (is_numeric($src_price)) {
                    $item_price = $src_price;
                }
            }


            if ($discount_opt['discount_type'] == 'fixed_discount_unit') {
                $disc_price = $item_price - $disc_price;
                if ($disc_price <= 0) {
                    return round($item_price, wc_get_price_decimals());
                }
                return round($disc_price, wc_get_price_decimals());
            }

            if ($discount_opt['discount_type'] == 'fixed_group_discount') {
                $disc_price = ($item_price * $qty) - $disc_price;
                if ($disc_price < 0) {
                    $disc_price = $item_price;
                }
                return round($disc_price / $qty, wc_get_price_decimals());
            }



            if ($discount_opt['discount_type'] == 'per_discount') {
                if ($disc_price <= 0) {
                    return round($item_price, wc_get_price_decimals());
                }
                if ($disc_price >= 100) {
                    return round($item_price, wc_get_price_decimals());
                }
                $disc_price = $item_price - (($disc_price / 100) * $item_price);
                return round($disc_price, wc_get_price_decimals());
            }
        }

        private static function get_group_part_repeat_count($part_products) {
            $total_qty = 0;
            foreach ($part_products['group'] as $key => $p_products) {
                $total_qty += $p_products['qty'];
            }
            return floor($total_qty / $part_products['qty']);
        }

        private static function get_all_group_count($grouped_products, $rep_count) {
            $all_qty = 0;
            $all_d_count = 0;
            foreach ($grouped_products as $g_products) {
                foreach ($g_products['group'] as $gg_products) {
                    foreach ($gg_products['products'] as $key => $product) {
                        for ($i = 0; $i < $product['quantity']; $i++) {
                            if ($all_d_count < ($g_products['qty'] * $rep_count)) {
                                $all_qty++;
                                $all_d_count++;
                            } else {
                                return $all_qty;
                            }
                        }
                    }
                }
            }
            return $all_qty;
        }

        private static function get_group_quantities($products, $qty_base_on) {
            $r_products = array();

            foreach ($products as $key => $g_products) {
                $cnt = 0;
                foreach (self::sort_quantities(WooPricely::get_quantities($g_products['group'], $qty_base_on)) as $d_key => $d_products) {
                    $r_products[$cnt]['g_' . $key]['qty'] = $g_products['qty'];
                    $r_products[$cnt]['g_' . $key]['group'][$d_key] = $d_products;
                    $cnt++;
                }

                $products[$key]['group'] = self::sort_quantities(WooPricely::get_quantities($g_products['group'], $qty_base_on));
            }




            return $r_products;
        }

        private static function sort_quantities($products) {
            $r_products = array();

            $max_qty = 0;
            foreach ($products as $key => $product) {
                if ($product['qty'] > $max_qty) {
                    $max_qty = $product['qty'];
                }
            }


            for ($i = $max_qty; $i >= 0; $i--) {
                foreach ($products as $key => $product) {
                    if ($product['qty'] == $i) {
                        $r_products[$key] = $product;
                    }
                }
            }
            return $r_products;
        }

        private static function merge_grouped_products($grouped_products) {
            $products = array();
            foreach ($grouped_products as $g_products) {
                foreach ($g_products['group'] as $key => $product) {
                    $products[$key] = $product;
                }
            }
            return $products;
        }

        private static function get_product_price($product, $base_on, $qty) {

            $item_price = WC()->cart->get_cart_item($product['cart_key'])['data']->get_price();
            if ($base_on != '' && $base_on != 'cart_price') {
                $src_price = WooPricely::get_product_price($product['key'], $base_on);
                if (is_numeric($src_price)) {
                    $item_price = $src_price;
                }
            }

            return $item_price * $qty;
        }

        private static function get_group_prices_details($prices) {
            $k_p = array();
            for ($i = 0; $i < count($prices); $i++) {
                $pri = '' . $prices[$i] . '';
                if (isset($k_p[$pri])) {
                    $k_p[$pri] ++;
                } else {
                    $k_p[$pri] = 1;
                }
            }
            $qty_details = array();
            foreach ($k_p as $key => $qty) {
                $qty_details[] = array(
                    'qty' => $qty,
                    'price' => $key
                );
            }
            return $qty_details;
        }

    }

    WooPricely_Checkout_Group_Prices::init();
}

