<?php
/**
 * Order refund model.
 *
 * @package flo-sync
 *
 * @phpcs:disable Generic.Commenting.DocComment.MissingShort
 */

namespace NMFS\Sync\Items\Orders\Models;

use NMFS\Shared;
use Northmill_Online_Shared_Sync\Northmill_Online_Shared\Abstracts\Hub_API\Models\Hub_API_Properties;
use Northmill_Online_Shared_Sync\Northmill_Online_Shared\Modules\Loggers\Log_Level_Enum;
use Northmill_Online_Shared_Sync\Northmill_Online_Shared\Modules\Sync\Orders\Models\Order_Base_Model;
use WC_Order;
use WC_Order_Refund;

defined( 'ABSPATH' ) || exit;

/**
 * Order_Refund_Model class.
 */
class Order_Refund_Model extends Order_Base_Model {

	/**
	 * Constructor.
	 *
	 * @param WC_Order_Refund $wc_order_refund The WooCommerce order refund instance.
	 *
	 * @return void
	 */
	public function __construct(
		protected readonly WC_Order_Refund $wc_order_refund
	) {
		$parent_order = wc_get_order( $this->wc_order_refund->get_parent_id() );

		parent::__construct( $parent_order );
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_order_id(): int {
		return $this->wc_order_refund->get_id();
	}

	/**
	 * Add refund order data to NM Flo order.
	 *
	 * @param array $parent_mf_order Northmill Flo order, from parent info.
	 *
	 * @return array Updated Northmill Flo order.
	 */
	public function refund_order_to_moreflo_order( array $parent_mf_order ): array {
		$order_no = $this->get_order_number();

		$refund_order = $parent_mf_order;

		$refund_order[ Hub_API_Properties::ORDER_EXTERNAL_REFERENCE ] = $this->get_external_reference( $order_no, 'MFS-' );
		$refund_order[ Hub_API_Properties::ORDER_OUR_REFERENCE ]      = $order_no;
		$refund_order[ Hub_API_Properties::ORDER_YOUR_ORDER_NUMBER ]  = $order_no;
		$refund_order[ Hub_API_Properties::ORDER_ROWS ]               = $this->get_refund_order_rows();
		$refund_order[ Hub_API_Properties::ORDER_PAYMENT_OPTION ]     = $this->get_hub_order_pay_method();
		$refund_order[ Hub_API_Properties::ORDER_PAYMENT_STATUS ]     = $this->get_order_pay_status();
		$refund_order[ Hub_API_Properties::ORDER_STATE ]              = $this->get_order_status_for_hub( 'refund' );

		return $refund_order;
	}

	/**
	 * Retrieves the order number.
	 * We pass it through the WC_Order model to make use of the 'woocommerce_order_number' filter.
	 *
	 * @return string
	 */
	public function get_order_number(): string {
		$order = new WC_Order( $this->wc_order_refund->get_id() );
		return $order->get_order_number();
	}

	/**
	 * Get order rows for order refund.
	 *
	 * @return array
	 */
	private function get_refund_order_rows(): array {
		$order_rows  = array();
		$order_items = $this->wc_order_refund->get_items( array( 'line_item', 'shipping' ) );

		$shipping_vat         = 25.0; // Default value, is updated below.
		$shipping_product_sku = $this->get_backoffice_account()->get_shipping_settings()->get_article_sku();
		$refund_part_sku      = $this->get_backoffice_account()->partial_refund_article_sku;

		if ( ! empty( $shipping_product_sku ) ) {
			$shipping_product_id = wc_get_product_id_by_sku( $shipping_product_sku );
			$shipping_product    = wc_get_product( $shipping_product_id );

			if ( is_a( $shipping_product, 'WC_Product' ) ) {
				$shipping_vat = $this->get_order_row_tax( $shipping_product );
			}
		}

		foreach ( $order_items as $item_data ) {
			if ( is_a( $item_data, 'WC_Order_Item_Shipping' ) && $shipping_product_sku ) {
				$price        = abs( $item_data->get_total() + $item_data->get_total_tax() );
				$vat          = $shipping_vat;
				$product_sku  = $shipping_product_sku;
				$product_name = __( 'Shipping', 'flo-sync' );
				$quantity     = -1;
				$dis          = 0;
			} elseif ( is_a( $item_data, 'WC_Order_Item_Product' ) ) {
				$product     = $item_data->get_product();
				$product_sku = $product->get_sku();
				$quantity    = $item_data->get_quantity();

				$price        = $product->get_regular_price();
				$product_name = $product->get_name();
				$dis          = 0;

				// Use stored take-away VAT rate for take-away refund items (Decision #40).
				if ( $item_data->get_meta( '_nm_is_take_away' ) ) {
					$vat = (float) $item_data->get_meta( '_nm_take_away_vat_rate' );
				} else {
					$vat = $this->get_order_row_tax( $product );
				}

				if ( 0 === $quantity ) {
					if ( ! $refund_part_sku ) {
						// Refund part sku has not been set, cannot create row for this product.
						Shared::instance()->logger->log(
							'sync',
							'Refund part sku has not been set',
							array(
								'product_name' => $product_name,
								'product_sku'  => $product_sku,
							),
							Log_Level_Enum::WARNING
						);
						continue;
					}

					$quantity    = -1;
					$product_sku = $refund_part_sku;
					$price       = abs( $item_data->get_total() + $item_data->get_total_tax() );
				} else {
					$original_sales_price = $this->wc_order->get_item_subtotal( $item_data, true, false );

					if ( $original_sales_price < $price ) {
						$dis = $price * $quantity - $original_sales_price * $quantity;
					}
				}
			} else {
				continue;
			}

			$item = array(
				Hub_API_Properties::ARTICLE_NUMBER   => $product_sku,
				Hub_API_Properties::ARTICLE_NAME     => $product_name,
				Hub_API_Properties::ARTICLE_QUANTITY => $quantity,
			);

			$item[ Hub_API_Properties::ARTICLE_AMOUNT_INC_VAT_EX_DISCOUNT ] = $price;
			$item[ Hub_API_Properties::ARTICLE_VAT_RATE ]                   = $vat;
			$item[ Hub_API_Properties::ARTICLE_DISCOUNT ]                   = $dis;

			if (
				! empty( $item[ Hub_API_Properties::ARTICLE_NUMBER ] ) &&
				! empty( $item[ Hub_API_Properties::ARTICLE_QUANTITY ] )
			) {
				$order_rows[] = $item;
			}
		}

		return $order_rows;
	}

	/**
	 * {@inheritDoc}
	 */
	protected function get_order_sync_failed_message(): string {
		return __( 'Hub order sync failed. Please contact Northmill.', 'flo-sync' );
	}

	/**
	 * {@inheritDoc}
	 */
	protected function get_order_sync_succeeded_message(): string {
		/*
		 * translators:
		 * %1$s: Hub order number
		 * %2$s: action taken on order (added/updated)
		 * %3$s: Hub account name.
		 */
		return __( 'Order refund #%1$s %2$s in Hub account %3$s.', 'flo-sync' );
	}
}
