<?php

if ( !defined( 'ABSPATH' ) ) {

    exit;
}

if ( !class_exists( 'Pricely_Amount_Types' ) ) {

    require_once (dirname( __FILE__ ) . '/amount-totals.php');
    require_once (dirname( __FILE__ ) . '/amount-tax.php');
    require_once (dirname( __FILE__ ) . '/amount-adjustments/amount-adjustments.php');

    require_once (dirname( __FILE__ ) . '/amount-types-order.php');
    require_once (dirname( __FILE__ ) . '/amount-types-order-items.php');

    class Pricely_Amount_Types {

        private static $instance;
        private $items_list;
        private $product_filter_types;
        private $amount_totals;
        private $amount_tax;
        private $amount_adjusments;
        private $amount_type_order;
        private $amount_type_order_items;

        public static function get_instance(): self {

            if ( !self::$instance ) {

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

            return self::$instance;
        }

        public function __construct() {

            $this->items_list = array();

            $this->product_filter_types = Pricely_Product_Filter_Types::get_instance();
            $this->amount_totals = Pricely_Amount_Totals::get_instance();
            $this->amount_tax = Pricely_Amount_Tax::get_instance();
            $this->amount_adjusments = Pricely_Amount_Adjustments::get_instance();

            //Amount Types
            $this->amount_type_order = new Pricely_Amount_Type_Order();
            $this->amount_type_order_items = new Pricely_Amount_Type_Order_Items();
        }

        public function calculate_amounts( $data, $items, $amounts_args ) {

            //set items list before any other processes
            $this->items_list = $items;

            //initialize amounts list
            $amounts = array(
                'id' => $amounts_args[ 'id' ],
                'inclusive_tax' => $amounts_args[ 'inclusive_tax' ],
                'totals' => array(),
                'total' => 0,
                'taxes' => array(),
                'total_tax' => 0,
            );

            //go through all amount_args and process them
            foreach ( $amounts_args[ 'amounts' ] as $amount_args ) {

                $amount_args[ 'context' ] = $amounts_args[ 'context' ];
                $amount_args[ 'parent_id' ] = $amounts_args[ 'id' ];

                //process single amount
                $amounts = $this->calculate_amount( $amounts, $data, $amount_args );
            }

            return apply_filters( 'pricely_calculate-amounts', $amounts, $data, $items, $amounts_args );
        }

        public function get_items( $args ) {

            $items = array();

            //product_args is always required
            if ( !isset( $args[ 'product_args' ] ) ) {

                $args[ 'product_args' ] = array();
            }

            //go through each item and validate them
            foreach ( $this->items_list as $key => $item ) {

                //set item context
                $item[ 'wc' ][ 'context' ] = $args[ 'context' ];

                //validate item
                if ( !$this->validate_item( $item, $args[ 'product_args' ] ) ) {

                    continue;
                }

                $items[ $key ] = $item;
            }

            return $items;
        }

        private function calculate_amount( $amounts, $data, $amount_args ) {

            $amount_data = array(
                'id' => $amount_args[ 'id' ],
                'parent_id' => $amount_args[ 'parent_id' ],
                'adjustment_type' => $amount_args[ 'adjustment_type' ],
                'inclusive_tax' => false,
                'totals' => array(),
                'total' => 0,
            );

            $amount_type = $amount_args[ 'amount_type' ];

            if ( $this->amount_type_order->can_calculate( $amount_type ) ) {

                $amount_data = $this->process_amount( $this->amount_type_order->calculate_amount( $amount_data, $data, $amount_args ), $amount_args[ 'tax_args' ], $amount_args[ 'context' ] );
            }

            if ( $this->amount_type_order_items->can_calculate( $amount_type ) ) {

                $amount_data = $this->process_amount( $this->amount_type_order_items->calculate_amount( $amount_data, $data, $amount_args ), $amount_args[ 'tax_args' ], $amount_args[ 'context' ] );
            }



            $filter_key = 'calculate-' . $amount_type . '-amount';

            if ( has_filter( 'pricely_' . $filter_key ) ) {

                $amount_data = apply_filters( 'pricely_' . $filter_key, $amount_data, $data, $amount_args );
            }

            return $this->amount_adjusments->process_amount( $amounts, $amount_data );
        }

        private function process_amount( $amount_data, $context ) {

            $items = $this->get_items( array( 'context' => $context ) );

            return $this->process_taxes( $this->amount_totals->process_amount( $amount_data, $items ) );
        }

        private function process_taxes( $amount_data ) {

            return $this->amount_tax->calculate( $amount_data );
        }

        private function validate_item( $item, $product_args ) {

            //validation not applicable
            if ( !count( $product_args ) ) {

                return true;
            }

            //validate product
            return $this->product_filter_types->validate_product( $item, $product_args );
        }

    }

}

