<?php

// If this file is called directly, abort.
if (!defined('WPINC')) {
	die;
}

class ProductFormatter {

	public static function format(WC_Product $product): array {
		$productType = $product->get_type();

		// Default values
		$price = null;
		$specialPrice = null;
		$childPrices = [];
		$childSpecialPrices = [];
		$configurableOptions = [];
		$stock = 0;
		$salableQty = 0;

		if ($productType === 'variable' || $productType === 'grouped') {
			$childrenIds = $product->get_children();
			if (!empty($childrenIds)) {
				$childrenProductsRaw = wc_get_products(['include' => $childrenIds, 'limit' => -1]);
				$childrenProductsMap = [];
				foreach ($childrenProductsRaw as $cp) {
					$childrenProductsMap[$cp->get_id()] = $cp;
				}

				$minPrice = null;
				$minSpecialPrice = null;
				$parentInStock = false;

				static $termsCache = [];

				foreach ($childrenIds as $childId) {
					if (!isset($childrenProductsMap[$childId])) {
						$child = wc_get_product($childId);
						if (!$child) continue;
					} else {
						$child = $childrenProductsMap[$childId];
					}

					$childPrice = (float) $child->get_regular_price();
					$childSpecialPrice = $child->get_sale_price() ? (float) $child->get_sale_price() : null;

					$childPrices[$childId] = $childPrice;
					$childSpecialPrices[$childId] = $childSpecialPrice;

					if ($productType === 'variable') {
						foreach ($child->get_attributes() as $attr_name => $attr_value_slug) {
							$code = str_replace('pa_', '', $attr_name);
							$taxonomy = wc_attribute_taxonomy_name($code);
							$termKey = $taxonomy . ':' . $attr_value_slug;

							if (!isset($termsCache[$termKey])) {
								$term = get_term_by('slug', $attr_value_slug, $taxonomy);
								if ($term && !is_wp_error($term)) {
									$termsCache[$termKey] = (string) $term->term_id;
								} else {
									$termsCache[$termKey] = null;
								}
							}

							$termId = $termsCache[$termKey];
							if ($termId !== null) {
								if (!isset($configurableOptions[$code])) {
									$configurableOptions[$code] = [];
								}
								if (!in_array((string) $termId, $configurableOptions[$code], true)) {
									$configurableOptions[$code][] = (string) $termId;
								}
							}
						}
					}

					if ($minPrice === null || $childPrice < $minPrice) {
						$minPrice = $childPrice;
					}

					if ($childSpecialPrice !== null && ($minSpecialPrice === null || $childSpecialPrice < $minSpecialPrice)) {
						$minSpecialPrice = $childSpecialPrice;
					}
					$price = $minPrice;
					$specialPrice = $minSpecialPrice;

					if ($child->is_in_stock()) {
						$parentInStock = true;
						$childQty = $child->get_stock_quantity();
						if ($childQty) {
							$salableQty += $childQty;
						}
					}

					$stock = $parentInStock ? 1 : 0;
				}

				if ($productType === 'grouped') {
					foreach ($product->get_attributes() as $attr_name => $attribute) {
						$code = str_replace('pa_', '', $attr_name);

						if (!isset($configurableOptions[$code])) {
							$configurableOptions[$code] = [];
						}

						if ($attribute->is_taxonomy() || taxonomy_exists($attr_name)) {
							$terms = wp_get_post_terms($product->get_id(), $attr_name);
							foreach ($terms as $term) {
								if (!in_array((string) $term->term_id, $configurableOptions[$code], true)) {
									$configurableOptions[$code][] = (string) $term->term_id;
								}
							}
						}
					}
				}
			}
		} else {
			$price = (float) $product->get_regular_price();
			$specialPrice = $product->get_sale_price() ? (float) $product->get_sale_price() : null;

			foreach ($product->get_attributes() as $attr_name => $attribute) {
				$code = str_replace('pa_', '', $attr_name);

				if ($attribute->is_taxonomy() || taxonomy_exists($attr_name)) {
					$terms = wp_get_post_terms($product->get_id(), $attr_name);
					foreach ($terms as $term) {
						if (!isset($configurableOptions[$code])) {
							$configurableOptions[$code] = [];
						}
						if (!in_array((string) $term->term_id, $configurableOptions[$code], true)) {
							$configurableOptions[$code][] = (string) $term->term_id;
						}
					}
				}
			}

			$stock = $product->is_in_stock() ? 1 : 0;
			$salableQty = $product->get_stock_quantity() ?? 0;
		}

		foreach ($configurableOptions as $code => $ids) {
			$allStrings = true;
			foreach ($ids as $v) {
				if (!is_string($v) && !is_numeric($v)) {
					$allStrings = false;
					break;
				}
			}

			if ($allStrings) {
				$indexed = [];
				$vals = array_values($ids);
				foreach ($vals as $index => $id) {
					$indexed[(string) $index] = (string) $id;
				}
				$configurableOptions[$code] = $indexed;
			} else {
				$configurableOptions[$code] = $ids;
			}
		}

		$attributes = self::getProductAttributes($product);

		$productData = [
			'type_id' => 'configurable',
			'entity_id' => (int) $product->get_id(),
			'name' => $product->get_name() ?? "",
			'link' => $product->get_permalink(),
			'status' => $product->get_status() === 'publish' ? 1 : 0,
			'stock' => $stock,
			'sku' => $product->get_sku(),
			'image' => self::getProductImage($product),
			'hover_image' => '',
			'description' => $product->get_description() ?? "",
			'short_description' => $product->get_short_description() ?? "",
			'created_at' => $product->get_date_created()?->date('Y-m-d H:i:s'),
			'updated_at' => $product->get_date_modified()?->date('Y-m-d H:i:s'),
			'price' => $price,
			'special_price' => $specialPrice,
			'child_prices' => (object) $childPrices,
			'child_special_prices' => (object) $childSpecialPrices,
			'categories' => array_map('strval', $product->get_category_ids()),
			'meta_title' => '',
			'meta_description' => '',
			'salable_qty' => $salableQty,
			'configurable_options' => (object) $configurableOptions,
			'child_products' => self::getChildProducts($product),
		] + $attributes;

		if (wc_review_ratings_enabled()) {
			$productData['total_reviews'] = (float) $product->get_average_rating();
			$productData['reviews'] = (int) $product->get_review_count();
		}

		return $productData;
	}

	private static function getProductImage($product) {
		$image_id = $product->get_image_id();
		return $image_id ? wp_get_attachment_url($image_id) : null;
	}

	private static function getChildProducts($product) {
		$childProducts = [];

		if (!in_array($product->get_type(), ['variable', 'grouped'], true)) {
			return $childProducts;
		}

		$childrenIds = $product->get_children();
		if (empty($childrenIds)) {
			return $childProducts;
		}

		$childrenProductsRaw = wc_get_products(['include' => $childrenIds, 'limit' => -1]);
		$childrenProductsMap = [];
		foreach ($childrenProductsRaw as $cp) {
			$childrenProductsMap[$cp->get_id()] = $cp;
		}

		static $termsCache = [];

		foreach ($childrenIds as $variation_id) {
			if (!isset($childrenProductsMap[$variation_id])) {
				$variation = wc_get_product($variation_id);
				if (!$variation) continue;
			} else {
				$variation = $childrenProductsMap[$variation_id];
			}

			$childConfigurableOptions = [];

			if ($product->is_type('variable')) {
				foreach ($variation->get_attributes() as $attr_name => $attr_value_slug) {
					$code = str_replace('pa_', '', $attr_name);
					$taxonomy = wc_attribute_taxonomy_name($code);
					$termKey = $taxonomy . ':' . $attr_value_slug;

					if (!isset($termsCache[$termKey])) {
						$term = get_term_by('slug', $attr_value_slug, $taxonomy);
						if ($term && !is_wp_error($term)) {
							$termsCache[$termKey] = (string) $term->term_id;
						} else {
							$termsCache[$termKey] = null;
						}
					}

					$termId = $termsCache[$termKey];
					if ($termId !== null) {
						$childConfigurableOptions[$code] = (string) $termId;
					}
				}
			}

			$childProducts[$variation_id] = [
				'type_id' => 'simple',
				'entity_id' => (int) $variation->get_id(),
				'sku' => $variation->get_sku(),
				'image' => self::getProductImage($variation),
				'hover_image' => '',
				'stock' => $variation->is_in_stock() ? 1 : 0,
				'salable_qty' => $variation->get_stock_quantity() ?? 0,
				'configurable_options' => $childConfigurableOptions,
			];
		}

		return $childProducts;
	}

	private static function getProductAttributes($product) {
		$attributes = [];

		if ($product->is_type('variable')) {
			$childrenIds = $product->get_children();
			if (!empty($childrenIds)) {
				$childrenProductsRaw = wc_get_products(['include' => $childrenIds, 'limit' => -1]);
				$childrenProductsMap = [];
				foreach ($childrenProductsRaw as $cp) {
					$childrenProductsMap[$cp->get_id()] = $cp;
				}

				static $termsCache = [];

				foreach ($childrenIds as $variation_id) {
					if (!isset($childrenProductsMap[$variation_id])) {
						$variation = wc_get_product($variation_id);
						if (!$variation) continue;
					} else {
						$variation = $childrenProductsMap[$variation_id];
					}

					foreach ($variation->get_attributes() as $attr_name => $attr_value_slug) {
						$code = str_replace('pa_', '', $attr_name);
						$taxonomy = wc_attribute_taxonomy_name($code);
						$termKey = $taxonomy . ':' . $attr_value_slug;

						if (!isset($termsCache[$termKey])) {
							$term = get_term_by('slug', $attr_value_slug, $taxonomy);
							if ($term && !is_wp_error($term)) {
								$termsCache[$termKey] = (string) $term->term_id;
							} else {
								$termsCache[$termKey] = $attr_value_slug;
							}
						}

						$termVal = $termsCache[$termKey];

						if (!isset($attributes[$code])) {
							$attributes[$code] = [];
						}

						if (!in_array((string) $termVal, $attributes[$code], true)) {
							$attributes[$code][] = (string) $termVal;
						}
					}
				}
			}
		} else {
			foreach ($product->get_attributes() as $attr_name => $attribute) {
				$code = str_replace('pa_', '', $attr_name);

				if ($attribute->is_taxonomy() || taxonomy_exists($attr_name)) {
					$terms = wp_get_post_terms($product->get_id(), $attr_name);
					$termIds = [];
					foreach ($terms as $term) {
						$termIds[] = (string) $term->term_id;
					}
					$attributes[$code] = $termIds;
				}
			}
		}

		foreach ($attributes as $code => $values) {
			$attributes[$code] = implode(',', $values);
		}

		return $attributes;
	}
}