<?php

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

class R123_WC_Order_Mapper {
	public static function map_order(WC_Order $order, string $trigger = 'manual'): array {
		$items    = [];
		$subtotal = 0.0;
		$tax      = 0.0;

		$product_ids        = [];
		$variation_ids      = [];
		$skus               = [];
		$product_categories = [];

		foreach ($order->get_items() as $item) {
			if (!($item instanceof WC_Order_Item_Product)) {
				continue;
			}

			$product      = $item->get_product();
			$quantity     = max(1, (float) $item->get_quantity());
			$item_total   = (float) $item->get_total();
			$item_tax     = (float) $item->get_total_tax();
			$unit_price   = $quantity > 0 ? ($item_total / $quantity) : $item_total;
			$tax_rate     = $item_total > 0 ? round(($item_tax / $item_total) * 100, 2) : 0.0;
			$variation_id = (int) $item->get_variation_id();
			$product_id   = (int) $item->get_product_id();

			$subtotal += $item_total;
			$tax      += $item_tax;

			if ($product_id > 0) {
				$product_ids[] = $product_id;
			}

			if ($variation_id > 0) {
				$variation_ids[] = $variation_id;
			}

			$description_parts = [];

			if ($product && $product->get_sku()) {
				$sku = (string) $product->get_sku();
				$description_parts[] = 'SKU: ' . $sku;
				$skus[] = $sku;
			}

			if ($variation_id > 0) {
				$description_parts[] = 'Variation ID: ' . $variation_id;
			}

			if ($product_id > 0) {
				$terms = get_the_terms($product_id, 'product_cat');

				if (is_array($terms)) {
					foreach ($terms as $term) {
						if (!empty($term->name)) {
							$product_categories[] = (string) $term->name;
						}
					}
				}
			}

			$items[] = [
				'name'        => (string) $item->get_name(),
				'quantity'    => $quantity,
				'unitPrice'   => round($unit_price, 2),
				'taxRate'     => $tax_rate,
				'description' => implode(' | ', $description_parts),
			];
		}

		foreach ($order->get_items('shipping') as $shipping_item) {
			$shipping_total = (float) $shipping_item->get_total();
			$shipping_tax   = (float) $shipping_item->get_total_tax();
			$tax_rate       = $shipping_total > 0 ? round(($shipping_tax / $shipping_total) * 100, 2) : 0.0;

			$subtotal += $shipping_total;
			$tax      += $shipping_tax;

			$items[] = [
				'name'        => (string) ($shipping_item->get_name() ?: 'Shipping'),
				'quantity'    => 1,
				'unitPrice'   => round($shipping_total, 2),
				'taxRate'     => $tax_rate,
				'description' => 'WooCommerce shipping',
			];
		}

		foreach ($order->get_items('fee') as $fee_item) {
			$fee_total = (float) $fee_item->get_total();
			$fee_tax   = (float) $fee_item->get_total_tax();
			$tax_rate  = $fee_total > 0 ? round(($fee_tax / $fee_total) * 100, 2) : 0.0;

			$subtotal += $fee_total;
			$tax      += $fee_tax;

			$items[] = [
				'name'        => (string) ($fee_item->get_name() ?: 'Fee'),
				'quantity'    => 1,
				'unitPrice'   => round($fee_total, 2),
				'taxRate'     => $tax_rate,
				'description' => 'WooCommerce fee',
			];
		}

		$discount_total = (float) $order->get_discount_total();

		$billing_name = trim((string) $order->get_billing_company());
		if ($billing_name === '') {
			$billing_name = trim($order->get_billing_first_name() . ' ' . $order->get_billing_last_name());
		}
		if ($billing_name === '') {
			$billing_name = 'WooCommerce Customer';
		}

		$address_parts = array_filter([
			$order->get_billing_address_1(),
			$order->get_billing_address_2(),
			trim($order->get_billing_postcode() . ' ' . $order->get_billing_city()),
			$order->get_billing_country(),
		]);

		$payment_method = (string) $order->get_payment_method();
		$notes          = trim((string) $order->get_customer_note());

		if ($notes === '') {
			$notes = 'WooCommerce order #' . $order->get_order_number();
		}

		$vat_number = '';
		$vat_meta_keys = [
			'_billing_vat_number',
			'billing_vat_number',
			'_billing_vat',
			'billing_vat',
			'_vat_number',
			'vat_number',
			'_eu_vat_number',
			'eu_vat_number',
		];

		foreach ($vat_meta_keys as $meta_key) {
			$meta_value = (string) $order->get_meta($meta_key);

			if ($meta_value !== '') {
				$vat_number = strtoupper(str_replace(' ', '', trim($meta_value)));
				break;
			}
		}

		$is_paid = $order->is_paid();

		$shipping_methods = [];
		foreach ($order->get_shipping_methods() as $shipping_method) {
			if (method_exists($shipping_method, 'get_name')) {
				$shipping_methods[] = (string) $shipping_method->get_name();
			}
		}

		$coupon_codes = $order->get_coupon_codes();

		$utm_source   = (string) $order->get_meta('_utm_source');
		$utm_medium   = (string) $order->get_meta('_utm_medium');
		$utm_campaign = (string) $order->get_meta('_utm_campaign');

		/**
		 * Optional future fields:
		 * send only if present / valid
		 */
		$due_date          = '';
		$service_from_date = '';
		$service_to_date   = '';

		$metadata = [
			'trigger'                => $trigger,
			'woo_order_id'           => (string) $order->get_id(),
			'woo_order_number'       => (string) $order->get_order_number(),
			'woo_status'             => (string) $order->get_status(),
			'payment_method'         => $payment_method,
			'payment_method_title'   => (string) $order->get_payment_method_title(),
			'payment_transaction_id' => (string) $order->get_transaction_id(),

			'billing_company'        => (string) $order->get_billing_company(),
			'shipping_company'       => (string) $order->get_shipping_company(),
			'billing_country'        => (string) $order->get_billing_country(),
			'shipping_country'       => (string) $order->get_shipping_country(),

			'shipping_method'        => implode(', ', $shipping_methods),
			'coupon_codes'           => implode(', ', $coupon_codes),

			'customer_id'            => (string) $order->get_customer_id(),
			'order_created_via'      => (string) $order->get_created_via(),

			'date_created'           => $order->get_date_created() ? $order->get_date_created()->date('c') : null,
			'date_paid'              => $order->get_date_paid() ? $order->get_date_paid()->date('c') : null,

			'prices_include_tax'     => $order->get_prices_include_tax(),

			'utm_source'             => $utm_source !== '' ? $utm_source : null,
			'utm_medium'             => $utm_medium !== '' ? $utm_medium : null,
			'utm_campaign'           => $utm_campaign !== '' ? $utm_campaign : null,

			'product_ids'            => array_values(array_unique(array_filter($product_ids))),
			'variation_ids'          => array_values(array_unique(array_filter($variation_ids))),
			'skus'                   => array_values(array_unique(array_filter($skus))),
			'product_categories'     => array_values(array_unique(array_filter($product_categories))),
		];

		$payload = [
			'externalOrderId' => (string) $order->get_order_number(),
			'customerName'    => $billing_name,
			'customerEmail'   => (string) $order->get_billing_email(),
			'customerAddress' => [
				'name'    => $billing_name,
				'address' => implode(', ', $address_parts),
				'phone'   => (string) $order->get_billing_phone(),
				'email'   => (string) $order->get_billing_email(),
			],
			'items'     => $items,
			'subtotal'  => round($subtotal, 2),
			'discount'  => round($discount_total, 2),
			'tax'       => round($tax, 2),
			'total'     => round((float) $order->get_total(), 2),
			'currency'  => strtoupper((string) ($order->get_currency() ?: 'EUR')),
			'isPaid'    => $is_paid,
			'notes'     => $notes,
			'metadata'  => $metadata,
		];

		if ($vat_number !== '') {
			$payload['customerTaxNumber'] = $vat_number;
		}

		if ($due_date !== '') {
			$payload['dueDate'] = $due_date;
		}

		if ($service_from_date !== '') {
			$payload['serviceFromDate'] = $service_from_date;
		}

		if ($service_to_date !== '') {
			$payload['serviceToDate'] = $service_to_date;
		}

		return $payload;
	}
}