<?php

if ( !defined( 'ABSPATH' ) ) {

    exit;
}

if ( !class_exists( 'Pricely_Pipeline_Cart' ) ) {

    class Pricely_Pipeline_Cart {

        private static $instance;
        private $cart;
        private $stack_counter;
        private $pre_processing_items;
        private $product_util;
        private $items_in_cart_key;

        public static function get_instance(): self {

            if ( !self::$instance ) {

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

            return self::$instance;
        }

        public function __construct() {

            $this->cart = false;
            $this->stack_counter = 0;
            $this->pre_processing_items = false;
            $this->items_in_cart_key = 'items_in_cart';

            add_action( 'woocommerce_before_calculate_totals', array( $this, 'before_calculate_totals' ), 99999 );
            add_action( 'woocommerce_after_calculate_totals', array( $this, 'after_calculate_totals' ), 999 ); // set_session uses 1000
            add_action( 'woocommerce_add_to_cart', array( $this, 'item_added_to_cart' ), 1, 6 );
        }

        public function item_added_to_cart( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {

            //check whether it's internal auto-add
            if ( $this->is_auto_adding() ) {

                return;
            }
            
            //clear all cache 
            $this->clear_cache();
        }

        public function before_calculate_totals( $cart ) {

            //increase cart process stack
            $this->cart_process_started();

            //Check whether cart processes can be initiated
            if ( !$this->can_process_cart() ) {

                return;
            }

            //Set current cart object
            $this->cart = $cart;

            //pre process pipeline data
            $this->pre_process_data( $cart );

            //pre process pipeline items data
            $this->pre_process_items( $cart );
            
            //process items auto-add
            $this->process_items_auto_add();

            //process coupons auto-add
            $this->process_coupons_auto_add();
        }

        public function after_calculate_totals( $cart ) {

            //set cart object
            $this->cart = $cart;

            //Check whether cart processes can be initiated
            if ( !$this->can_process_cart() ) {

                $this->cart_process_stopped();

                return;
            }
            
            //process cart messages
            $this->process_cart_messages( $cart );

            $this->process_order_data();

            $this->save_data();

            //decrease cart process stack
            $this->cart_process_stopped();
        }

        public function is_pre_processing_items() {
            
            if ( !class_exists( 'Pricely_Cart_Virtual' ) ) {

                return $this->pre_processing_items;
            }

            $is_virtual_processing = Pricely_Cart_Virtual::get_instance()->is_pre_processing_item();

            if ( false !== $is_virtual_processing ) {

                return $is_virtual_processing;
            }

            return $this->pre_processing_items;
        }

        public function is_calculating() {

            return ( $this->stack_counter > 0 );
        }

        public function can_process_cart() {
            
            if ( $this->is_auto_adding() ) {

                return true;
            }

            if ( $this->stack_counter == 1 ) {

                return true;
            }

            return false;
        }

        public function get_cart() {

            if ( !$this->cart ) {

                return WC()->cart;
            }

            return $this->cart;
        }

        private function clear_cache() {

            $pipeline = Pricely_Pipeline::get_instance();

            $pipeline->clear_cache();

            $this->save_data();
        }

        private function pre_process_items( $cart ) {

            if ( !$this->can_process_item_data() ) {

                return;
            }

            $this->pre_processing_items = true;
            $items_in_cart = array();

            foreach ( $cart->get_cart_contents() as $key => $item ) {

                $cart_key = $key;
                $quantity = $item[ 'quantity' ];
                $item_key = $this->get_item_key( $item[ 'product_id' ], $item[ 'variation_id' ] );


                $item_in_cart = array(
                    'cart_key' => $cart_key,
                    'quantity' => $quantity,
                    'price' => $item[ 'data' ]->get_price()
                );

                $items_in_cart[ $item_key ] = apply_filters( 'pricely_process-pipeline-item-in-cart', $item_in_cart, $item, $cart );
            }

            Pricely_Session::get_instance()->set( $this->items_in_cart_key, $items_in_cart );

            $this->pre_processing_items = false;
        }

        private function pre_process_data( $cart ) {

            if ( !$this->can_process_item_data() ) {

                return;
            }

            Pricely_Cart_Session::get_instance()->load_cart_data( $cart );
        }
        
        private function process_items_auto_add() {

            if ( !class_exists( 'Pricely_Pipeline_Cart_Items_Auto_Add' ) ) {

                return;
            }

            if ( $this->is_auto_adding() ) {

                $this->clear_cache();

                return;
            }

            Pricely_Pipeline_Cart_Items_Auto_Add::get_instance()->process_auto_add( $this->cart );
        }

        private function process_coupons_auto_add() {

            Pricely_Pipeline_Coupons::get_instance()->process_coupons_auto_add( $this->cart );
        }
        
        private function process_cart_messages( $cart ) {

            if ( !class_exists( 'Pricely_Pipeline_Cart_Messages' ) ) {

                return;
            }

            Pricely_Pipeline_Cart_Messages::get_instance()->pre_process_messages( $cart );
        }

        private function process_order_data() {

            Pricely_Pipeline_Order::get_instance()->process_cart_data();
        }

        private function save_data() {

            if ( !$this->can_process_item_data() ) {

                return;
            }

            Pricely_Cache::get_instance()->save();
        }

        private function get_item_key( $product_id, $variation_id ) {

            if ( is_null( $this->product_util ) ) {

                $this->product_util = Pricely_Product::get_instance();
            }

            return $this->product_util->get_product_key( $product_id, $variation_id );
        }

        private function can_process_item_data() {
            
            if ( $this->is_auto_adding() ) {

                return true;
            }

            if ( $this->is_cache_valid() ) {

                return false;
            }

            return true;
        }

        private function cart_process_started() {
            
            if ( $this->is_auto_adding() ) {

                return;
            }

            $this->stack_counter++;
        }

        private function cart_process_stopped() {
            
            if ( $this->is_auto_adding() ) {

                return;
            }

            $this->stack_counter--;

            if ( $this->stack_counter < 0 ) {

                $this->stack_counter = 0;
            }
        }

        private function is_cache_valid() {

            return Pricely_Cache::get_instance()->is_valid_data();
        }
        
        private function is_auto_adding() {

            if ( !class_exists( 'Pricely_Pipeline_Cart_Items_Auto_Add' ) ) {

                return false;
            }

            return Pricely_Pipeline_Cart_Items_Auto_Add::get_instance()->is_auto_adding();
        }

    }

    Pricely_Pipeline_Cart::get_instance();
}

