<?php

if ( ! defined( 'ABSPATH' ) )
    exit; // Exit if accessed directly

if ( ! class_exists( 'TC_Export_Totals' ) ) {

    class TC_Export_Totals {

        var $order = [];
        var $item_id = '';
        var $instances = [];
        var $event_id = '';
        var $current_instance_id = '';

        function __construct( $order, $event_id = '' ) {

            if ( is_int( $order ) ) {
                $order = new TC_Order( $order );
            }

            $this->instances = self::get_instances( (int) $order->details->ID );

            if ( ! $event_id ) {
                $event_id = isset( $_POST[ 'tc_export_csv_event_data' ] ) ? (int) $_POST[ 'tc_export_csv_event_data' ] : '';
            }

            $this->event_id = $event_id;
            $this->order = $order;
        }

        /**
         * Initialize event totals object.
         *
         * @return stdClass
         * @throws Exception
         */
        function get_event_totals() {

            $subtotal = 0; $total = 0; $discount = 0; $fee = 0; $tax = 0;

            foreach ( $this->instances as $id ) {

                $this->current_instance_id = $id;
                $event_id = get_post_meta( $id, 'event_id', true );

                if ( $event_id == $this->event_id ) {

                    $subtotal += (float) self::get_ticket_subtotal();
                    $total += (float) self::get_ticket_total();
                    $discount += (float) self::get_ticket_discount();
                    $fee += (float) self::get_ticket_fee();
                    $tax += (float) self::get_ticket_tax();
                }
            }

            $totals = new stdClass();
            $totals->subtotal = round( $subtotal, 2 );
            $totals->total = round( $total, 2 );
            $totals->discount = round( $discount, 2 );
            $totals->fee = round( $fee, 2 );
            $totals->tax = round( $tax, 2 );

            return $totals;
        }

        /**
         * Initialize ticket totals object.
         *
         * @param int $instance_id
         * @return stdClass
         * @throws Exception
         */
        function get_ticket_totals( $instance_id = 0 ) {

            if ( $instance_id ) {
                $this->current_instance_id = $instance_id;
            }

            $totals = new stdClass();
            $totals->subtotal = round( (float) self::get_ticket_subtotal(), 2 );
            $totals->total = round( (float) self::get_ticket_total(), 2 );
            $totals->discount = round( (float) self::get_ticket_discount(), 2 );
            $totals->fee = round( (float) self::get_ticket_fee(), 2 );
            $totals->tax = round( (float) self::get_ticket_tax(), 2 );

            return $totals;
        }

        /**
         * Initialize order totals object.
         */
        function get_order_totals() {

            $order_id = $this->order->details->ID;
            $totals = new stdClass();

            switch ( get_post_type( $order_id ) ) {

                case 'tc_orders':
                    $payment_info = get_post_meta( $order_id, 'tc_payment_info', true );
                    $totals->total = (float) $payment_info[ 'total' ] ?? 0;
                    $totals->subtotal = (float) $payment_info[ 'subtotal' ] ?? 0;
                    $totals->discount = (float) $payment_info[ 'discount' ] ?? 0;
                    $totals->fee = (float) $payment_info[ 'fees_total' ] ?? 0;
                    $totals->tax = (float) $payment_info[ 'tax_total' ] ?? 0;
                    break;

                case 'shop_order':
                    $order = new WC_Order( $order_id );
                    $totals->total = $order->get_total();
                    $totals->subtotal = $order->get_subtotal();
                    $totals->discount = $order->get_total_discount();
                    $totals->tax = $order->get_total_tax();
                    break;
            }

            return $totals;
        }

        /**
         * Get Ticket Subtotal base from meta value.
         * Tickera Standalone
         *
         * @return bool|mixed
         * @throws Exception
         */
        function get_ticket_subtotal() {

            switch ( get_post_type( $this->order->details->ID ) ) {

                case 'tc_orders':
                    return get_post_meta( $this->current_instance_id, 'ticket_subtotal', true );
                    break;

                case 'shop_order':
                    return self::get_woo_ticket_subtotal();
                    break;

                default:
                    return false;
            }
        }

        /**
         * Get Ticket Total from meta value.
         * Tickera Standalone
         *
         * @return bool|mixed
         * @throws Exception
         */
        function get_ticket_total() {

            switch ( get_post_type( $this->order->details->ID ) ) {

                case 'tc_orders':
                    return get_post_meta( $this->current_instance_id, 'ticket_total', true );
                    break;

                case 'shop_order':
                    return self::get_woo_ticket_total();
                    break;

                default:
                    return false;
            }
        }

        /**
         * Get Ticket Discount base from meta value.
         * Tickera Standalone
         *
         * @return bool|mixed
         * @throws Exception
         */
        function get_ticket_discount() {

            switch ( get_post_type( $this->order->details->ID ) ) {

                case 'tc_orders':
                    return get_post_meta( $this->current_instance_id, 'ticket_discount', true );
                    break;

                case 'shop_order':
                    return self::get_woo_ticket_discount();
                    break;

                default:
                    return false;
            }
        }

        /**
         * Get Ticket Fee from meta value.
         * Tickera Standalone
         *
         * @return bool|mixed
         */
        function get_ticket_fee() {

            switch ( get_post_type( $this->order->details->ID ) ) {

                case 'tc_orders':
                    return get_post_meta( $this->current_instance_id, 'ticket_fee', true );
                    break;

                default:
                    return false;
            }
        }

        /**
         * Get Ticket Tax base from meta value.
         * Tickera Standalone
         *
         * @return bool|mixed
         * @throws Exception
         */
        function get_ticket_tax() {

            switch ( get_post_type( $this->order->details->ID ) ) {

                case 'tc_orders':
                    return get_post_meta( $this->current_instance_id, 'ticket_tax', true );
                    break;

                case 'shop_order':
                    return self::get_woo_ticket_tax();
                    break;

                default:
                    return false;
            }
        }

        /**
         * Get Woocommerce Ticket Subtotal base from order line item
         *
         * @return bool|mixed
         * @throws Exception
         */
        function get_woo_ticket_subtotal() {

            $item_id = get_post_meta( $this->current_instance_id, 'item_id', true );

            if ( ! $item_id ) {
                $item_ids = self::maybe_get_woo_order_item_ids();
                $item_id = $item_ids[ $this->current_instance_id ] ?? '';
            }

            if ( ! $item_id ) {
                return false;
            }

            $quantity = ( $item_id ) ? wc_get_order_item_meta( $item_id, '_qty', true ) : false;
            $subtotal = ( $quantity ) ? wc_get_order_item_meta( $item_id, '_line_subtotal', true ) : false;
            return (float) ( $subtotal / $quantity );
        }

        /**
         * Get Woocommerce Ticket Discount base from order line item
         * @return bool|string
         * @throws Exception
         */
        function get_woo_ticket_discount() {

            $item_id = get_post_meta( $this->current_instance_id, 'item_id', true );

            if ( ! $item_id ) {
                $item_ids = self::maybe_get_woo_order_item_ids();
                $item_id = $item_ids[ $this->current_instance_id ] ?? '';
            }

            if ( ! $item_id ) {
                return false;
            }

            $subtotal = wc_get_order_item_meta( $item_id, '_line_subtotal', true );
            $total = wc_get_order_item_meta( $item_id, '_line_total', true );
            return (float) ( $subtotal - $total );
        }

        /**
         * Get Woocommerce Ticket Tax base from order line item
         *
         * @return bool|mixed
         * @throws Exception
         */
        function get_woo_ticket_tax() {

            $item_id = get_post_meta( $this->current_instance_id, 'item_id', true );

            if ( ! $item_id ) {
                $item_ids = self::maybe_get_woo_order_item_ids();
                $item_id = $item_ids[ $this->current_instance_id ] ?? '';
            }

            return ( $item_id ) ? wc_get_order_item_meta( $item_id, '_line_tax', true ) : false;
        }

        /**
         * Get Woocommerce Ticket Total base from order line item
         *
         * @return bool|mixed
         * @throws Exception
         */
        function get_woo_ticket_total() {

            $item_id = get_post_meta( $this->current_instance_id, 'item_id', true );

            if ( ! $item_id ) {
                $item_ids = self::maybe_get_woo_order_item_ids();
                $item_id = $item_ids[ $this->current_instance_id ] ?? '';
            }

            if ( ! $item_id ) {
                return false;
            }

            $quantity = ( $item_id ) ? wc_get_order_item_meta( $item_id, '_qty', true ) : false;
            $total = ( $quantity ) ? wc_get_order_item_meta( $item_id, '_line_total', true ) : false;

            return (float) $total / $quantity;
        }

        /**
         * Collection of Ticket Instances of an Order
         *
         * @param $order_id
         * @return int[]|WP_Post[]
         */
        function get_instances( $order_id ) {

            $order_status = get_post_status( $order_id );
            $wc_order_status_values = array( 'any', 'wc-cancelled' );
            $post_statuses = in_array( $order_status, $wc_order_status_values ) ? array( 'trash', 'publish' ) : 'publish';

            return get_posts( [
                'post_parent'       => $order_id,
                'post_type'         => 'tc_tickets_instances',
                'post_status'       => $post_statuses,
                'fields'            => 'ids',
                'posts_per_page'    => -1,
            ]);
        }

        /**
         * Generate an array variable that contains ticket_instance_id and its associated item_id.
         *
         * @return mixed
         */
        function maybe_get_woo_order_item_ids() {

            $order_id = $this->order->details->ID;
            $order = new WC_Order( $order_id );
            $items = $order->get_items();

            /**
             * Initialize $order_line_item_ids array variable.
             * To be used to compare multiple ticket_type_ids with different item_ids within an order line items.
             */
            $order_line_item_ids = [];
            foreach ( $items as $item_id => $item ) {

                $variation_id = $item->get_variation_id();
                $product_id = $item->get_product_id();
                $quantity = $item->get_quantity();

                $ticket_type_id = ( !$variation_id ) ? $product_id : $variation_id;
                $is_ticket = get_post_meta( $product_id, '_tc_is_ticket', true );

                if ( $is_ticket ) {
                    $order_line_item_ids[ $ticket_type_id ][] = [
                        'quantity' => $quantity,
                        'item_id' => $item_id
                    ];
                }
            }

            /**
             * Initialize $cart_contents array variable.
             * Consist of ticket_instance_id and its associated item_id
             */
            $cart_contents = [];
            $ticket_instances = self::get_instances( $order_id );
            foreach ( $ticket_instances as $ticket_instance_id ) {

                $ticket_type_id = get_post_meta( $ticket_instance_id, 'ticket_type_id', true );

                if ( isset( $order_line_item_ids[ $ticket_type_id ] ) ) {

                    foreach ( $order_line_item_ids[ $ticket_type_id ] as $key => $line_item ) {

                        if ( $line_item[ 'quantity' ] ) {
                            $cart_contents[ $ticket_instance_id ] = $line_item[ 'item_id' ];
                            $order_line_item_ids[ $ticket_type_id ][ $key ][ 'quantity' ]--;
                            break;
                        }
                    }
                }
            }

            return $cart_contents;
        }
    }
}
