<?php

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

if ( !class_exists( 'Pricely_Cart_Session' ) ) {

    class Pricely_Cart_Session {

        private static $instance = null;
        private $taxonomy_util;
        private $session;
        private $cart_data_key;
        private $cart_data;
        private $default_cart_data;
        private $cart;
        private $current_user;
        private $item_data_keys;

        public static function get_instance(): self {

            if ( null == self::$instance ) {

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

            return self::$instance;
        }

        private function __construct() {

            $this->cart_data = false;
            $this->cart_data_key = 'data';
        }

        public function get_cart_data() {

            if ( false == $this->cart_data ) {

                $this->get_session();
            }

            if ( !count( $this->cart_data ) ) {

                $this->cart_data = $this->get_default_cart_data();
            }

            return $this->cart_data;
        }

        Public function clear_cart_data() {

            $this->cart_data = false;
        }

        public function load_cart_data( $cart ) {

            $this->cart = $cart;

            $this->cart_data = $this->process_cart_data( array() );

            $this->set_session();
        }

        private function process_cart_data( $cart_data ) {

            return $this->process_items( $cart_data );
        }

        private function process_items( $cart_data ) {

            $cart_items = array();

            foreach ( $this->cart->get_cart_contents() as $item ) {

                $product_key = Pricely_Product::get_instance()->get_product_key( $item[ 'product_id' ], $item[ 'variation_id' ] );

                $cart_items[ $product_key ] = $this->process_item( $item );
            }

            $cart_data[ 'items' ] = $cart_items;

            return $this->process_customer( $cart_data );
        }

        private function process_item( $cart_item ) {

            $item_data = array(
                'product_id' => $cart_item[ 'product_id' ],
                'variation_id' => $cart_item[ 'variation_id' ],
            );

            $product_data = $this->process_item_data( $cart_item );

            if ( !count( $product_data ) ) {

                return $item_data;
            }

            foreach ( $this->map_item_data_keys() as $item_data_key ) {

                if ( !isset( $product_data[ $item_data_key ] ) ) {

                    continue;
                }

                $item_data[ $item_data_key ] = $product_data[ $item_data_key ];
            }

            return $item_data;
        }

        private function process_item_data( $cart_item ) {

            $pricely_product = Pricely_Product::get_instance();

            if ( $cart_item[ 'variation_id' ] > 0 ) {

                $variation = $cart_item[ 'data' ];

                $product = $pricely_product->get_product( $cart_item[ 'product_id' ] );

                if ( $product ) {

                    return $pricely_product->get_data( $product, $variation );
                } else {

                    return array();
                }
            }

            return $pricely_product->get_data( $cart_item[ 'data' ] );
        }

        private function process_customer( $cart_data ) {

            $cart_data[ 'customer' ] = array();

            $customer = WC()->session->get( 'customer', false );

            if ( !$customer ) {

                $customer = $this->get_current_user( false );
            }

            if ( $customer ) {

                $cart_data[ 'customer' ] = array(
                    'id' => $customer[ 'id' ],
                    'email' => $customer[ 'email' ],
                );
            }

            return $cart_data;
        }

        private function get_default_cart_data() {

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

                return $this->default_cart_data;
            }

            $default = array(
                'items' => array(),
            );

            $this->default_cart_data = $this->process_customer( $default );

            return $this->default_cart_data;
        }

        private function get_current_user( $defualt ) {

            if ( is_array( $this->current_user ) && count( $this->current_user ) ) {

                return $this->current_user;
            }

            $user_data = wp_get_current_user();

            if ( !$user_data instanceof WP_User ) {

                return $defualt;
            }

            if ( !$user_data->ID ) {

                return $defualt;
            }

            $this->current_user = array(
                'id' => $user_data->ID,
                'email' => $user_data->get( 'user_email' )
            );

            return $this->current_user;
        }

        private function map_item_data_keys() {

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

                return $this->item_data_keys;
            }

            $this->item_data_keys = array(
                'tax_status',
                'tax_class',
                'is_taxable',
            );

            foreach ( $this->get_taxonomy_keys() as $terms_key ) {

                $this->item_data_keys[] = $terms_key;
            }

            if ( has_filter( 'pricely_map-cart-session-item-data-keys' ) ) {

                $this->item_data_keys = apply_filters( 'pricely_map-cart-session-item-data-keys', $this->item_data_keys );
            }

            return $this->item_data_keys;
        }

        private function get_session() {

            $this->cart_data = Pricely_Session::get_instance()->get( $this->cart_data_key, array() );
        }

        private function set_session() {

            Pricely_Session::get_instance()->set( $this->cart_data_key, $this->cart_data );
        }

        private function get_taxonomy_keys() {

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

                $this->taxonomy_util = Pricely_Taxonomy_Util::get_instance();
            }

            $taxonomies = array();

            foreach ( $this->taxonomy_util->get_taxonomies() as $taxonomy_data ) {

                $taxonomies[] = $taxonomy_data[ 'terms_key' ];
            }

            return $taxonomies;
        }

    }

    Pricely_Cart_Session::get_instance();
}
