<?php

namespace BWDK\Woo\Order;

use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use BWDK\Support\Constant;
use Exception;
use WC_Geolocation;
use WC_Order;
use WP_Error;

class OrderService
{

    public function createFromCurrentCart(array $data): WC_Order
    {
        $order_id = apply_filters('woocommerce_create_order', null, $this);
        if ($order_id) {
            $order = wc_get_order($order_id);
            if ($order) {
                return $order;
            }
        }

        $order_id   = absint(WC()->session->get('order_awaiting_payment'));
        $cart_hash  = WC()->cart->get_cart_hash();
        $gateways   = WC()->payment_gateways->get_available_payment_gateways();
        $order      = $order_id ? wc_get_order($order_id) : null;

        if ($order && $order->has_cart_hash($cart_hash) && $order->has_status([OrderStatus::PENDING, OrderStatus::FAILED])) {
            do_action('woocommerce_resume_order', $order_id);
            $order->remove_order_items();
        } else {
            $order = new WC_Order();
        }

        $fields_prefix   = ['shipping' => true, 'billing' => true];
        $shipping_fields = ['shipping_method' => true, 'shipping_total' => true, 'shipping_tax' => true];

        foreach ($data as $key => $value) {
            if (is_callable([$order, "set_{$key}"])) {
                $order->{"set_{$key}"}($value);
            } elseif (isset($fields_prefix[current(explode('_', $key))])) {
                if (!isset($shipping_fields[$key])) {
                    $order->update_meta_data('_' . $key, $value);
                }
            }
        }

        if (isset($data['billing_email'])) {
            $order->hold_applied_coupons($data['billing_email']);
        }

        $order->set_created_via('checkout');
        $order->set_cart_hash($cart_hash);
        $order->set_customer_id(apply_filters('woocommerce_checkout_customer_id', get_current_user_id()));
        $order->set_currency(get_woocommerce_currency());
        $order->set_prices_include_tax('yes' === get_option('woocommerce_prices_include_tax'));
        $order->set_customer_ip_address(WC_Geolocation::get_ip_address());
        $order->set_customer_user_agent(wc_get_user_agent());
        $order->set_customer_note($data['order_comments'] ?? '');

        $order->set_payment_method(isset($gateways[$data['payment_method']]) ? $gateways[$data['payment_method']] : ($data['payment_method'] ?? ''));


        $this->set_data_from_cart($order);


        if ($order->has_cogs() && $this->cogs_is_enabled()) {
            $order->calculate_cogs_total_value();
        }

        $order->update_meta_data(Constant::META_BWDK_WOO_ORDER_UUID,wp_generate_uuid4());

        do_action('woocommerce_checkout_create_order', $order, $data);




        return $order;
    }


    public function set_data_from_cart(&$order)
    {
        $order_vat_exempt = WC()->cart->get_customer()->get_is_vat_exempt() ? 'yes' : 'no';

        $order->add_meta_data('is_vat_exempt', $order_vat_exempt, true);

        $order->set_shipping_total(WC()->cart->get_shipping_total());
        $order->set_discount_total(WC()->cart->get_discount_total());
        $order->set_discount_tax(WC()->cart->get_discount_tax());
        $order->set_cart_tax(WC()->cart->get_cart_contents_tax() + WC()->cart->get_fee_tax());
        $order->set_shipping_tax(WC()->cart->get_shipping_tax());
        $order->set_total(WC()->cart->get_total('edit'));

        $this->create_order_line_items($order, WC()->cart);
        $this->create_order_fee_lines($order, WC()->cart);
        $this->create_order_shipping_lines($order, WC()->session->get('chosen_shipping_methods'), WC()->shipping()->get_packages());
        $this->create_order_tax_lines($order, WC()->cart);
        $this->create_order_coupon_lines($order, WC()->cart);
    }

    protected function cogs_is_enabled(?string $doing_it_wrong_function_name = null): bool
    {
        if (wc_get_container()->get(CostOfGoodsSoldController::class)->feature_is_enabled()) {
            return true;
        }
        if ($doing_it_wrong_function_name) {
            wc_get_container()->get(LegacyProxy::class)->call_function(
                'wc_doing_it_wrong',
                $doing_it_wrong_function_name,
                'The Cost of Goods sold feature is disabled, thus the method called will do nothing and will return dummy data.',
                '9.5.0'
            );
        }
        return false;
    }



    public function create_order_line_items(&$order, $cart)
    {
        foreach ($cart->get_cart() as $cart_item_key => $values) {
            $item                       = apply_filters('woocommerce_checkout_create_order_line_item_object', new \WC_Order_Item_Product(), $cart_item_key, $values, $order);
            $product                    = $values['data'];
            $item->legacy_values        = $values; // deprecated
            $item->legacy_cart_item_key = $cart_item_key; // deprecated

            $item->set_props([
                'quantity'     => $values['quantity'],
                'variation'    => $values['variation'],
                'subtotal'     => $values['line_subtotal'],
                'total'        => $values['line_total'],
                'subtotal_tax' => $values['line_subtotal_tax'],
                'total_tax'    => $values['line_tax'],
                'taxes'        => $values['line_tax_data'],
            ]);

            if ($product) {
                $item->set_props([
                    'name'         => $product->get_name(),
                    'tax_class'    => $product->get_tax_class(),
                    'product_id'   => $product->is_type(ProductType::VARIATION) ? $product->get_parent_id() : $product->get_id(),
                    'variation_id' => $product->is_type(ProductType::VARIATION) ? $product->get_id() : 0,
                ]);
            }

            $item->set_backorder_meta();

            do_action('woocommerce_checkout_create_order_line_item', $item, $cart_item_key, $values, $order);

            $order->add_item($item);
        }
    }

    public function create_order_fee_lines(&$order, $cart)
    {
        foreach ($cart->get_fees() as $fee_key => $fee) {
            $item                 = new \WC_Order_Item_Fee();
            $item->legacy_fee     = $fee; // deprecated
            $item->legacy_fee_key = $fee_key; // deprecated
            $item->set_props([
                'name'      => $fee->name,
                'tax_class' => $fee->taxable ? $fee->tax_class : 0,
                'amount'    => $fee->amount,
                'total'     => $fee->total,
                'total_tax' => $fee->tax,
                'taxes'     => ['total' => $fee->tax_data],
            ]);

            do_action('woocommerce_checkout_create_order_fee_item', $item, $fee_key, $fee, $order);

            $order->add_item($item);
        }
    }

    public function create_order_shipping_lines(&$order, $chosen_shipping_methods, $packages)
    {
        foreach ($packages as $package_key => $package) {
            if (isset($chosen_shipping_methods[$package_key], $package['rates'][$chosen_shipping_methods[$package_key]])) {
                $shipping_rate            = $package['rates'][$chosen_shipping_methods[$package_key]];
                $item                     = new \WC_Order_Item_Shipping();
                $item->legacy_package_key = $package_key; // deprecated
                $item->set_props([
                    'method_title' => $shipping_rate->label,
                    'method_id'    => $shipping_rate->method_id,
                    'instance_id'  => $shipping_rate->instance_id,
                    'total'        => wc_format_decimal($shipping_rate->cost),
                    'taxes'        => ['total' => $shipping_rate->taxes],
                    'tax_status'   => $shipping_rate->tax_status,
                ]);

                foreach ($shipping_rate->get_meta_data() as $key => $value) {
                    $item->add_meta_data($key, $value, true);
                }

                do_action('woocommerce_checkout_create_order_shipping_item', $item, $package_key, $package, $order);

                $order->add_item($item);
            }
        }
    }

    public function create_order_tax_lines(&$order, $cart)
    {
        foreach (array_keys($cart->get_cart_contents_taxes() + $cart->get_shipping_taxes() + $cart->get_fee_taxes()) as $tax_rate_id) {
            if ($tax_rate_id && apply_filters('woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated') !== $tax_rate_id) {
                $item = new \WC_Order_Item_Tax();
                $item->set_props([
                    'rate_id'            => $tax_rate_id,
                    'tax_total'          => $cart->get_tax_amount($tax_rate_id),
                    'shipping_tax_total' => $cart->get_shipping_tax_amount($tax_rate_id),
                    'rate_code'          => \WC_Tax::get_rate_code($tax_rate_id),
                    'label'              => \WC_Tax::get_rate_label($tax_rate_id),
                    'compound'           => \WC_Tax::is_compound($tax_rate_id),
                    'rate_percent'       => \WC_Tax::get_rate_percent_value($tax_rate_id),
                ]);

                do_action('woocommerce_checkout_create_order_tax_item', $item, $tax_rate_id, $order);

                $order->add_item($item);
            }
        }
    }

    public function create_order_coupon_lines(&$order, $cart)
    {
        foreach ($cart->get_coupons() as $code => $coupon) {
            $item = new \WC_Order_Item_Coupon();
            $item->set_props([
                'code'         => $code,
                'discount'     => $cart->get_coupon_discount_amount($code),
                'discount_tax' => $cart->get_coupon_discount_tax_amount($code),
            ]);

            $coupon_info = $coupon->get_short_info();
            $item->add_meta_data('coupon_info', $coupon_info);

            do_action('woocommerce_checkout_create_order_coupon_item', $item, $code, $coupon, $order);

            $order->add_item($item);
        }
    }
}
