<?php

namespace ShopManagerPro\Products;

use ShopManagerPro\ACF\ACFRepository;
use ShopManagerPro\ACF\DTO\ACFCollection;
use ShopManagerPro\Premium\CustomFields\CustomFieldDiscoveryService;
use ShopManagerPro\Premium\CustomFields\DTO\CustomFieldsCollection;
use ShopManagerPro\Premium\CustomFields\DTO\Generated\CustomFieldsResponseItemsItemConfigDataType;
use ShopManagerPro\Products\Fields\DTO\ProductFieldGroupType;
use ShopManagerPro\Products\Fields\ProductFieldRepository;
use ShopManagerPro\Shared\Utils\Logger;
use ShopManagerPro\Taxonomies\DTO\TaxonomyCollection;

class ProductRepository {
	public static function getProductAttributes() {
		$attribute_taxonomies = wc_get_attribute_taxonomies();
		$result = [];
		if (!empty($attribute_taxonomies)) {
			foreach ($attribute_taxonomies as $tax) {
				$taxonomy_name = wc_attribute_taxonomy_name($tax->attribute_name);
				$terms = get_terms(['taxonomy' => $taxonomy_name, 'hide_empty' => false]);
				$attribute_terms = [];
				if (!is_wp_error($terms) && !empty($terms) && is_array($terms)) {
					foreach ($terms as $term) {
						if (!($term instanceof \WP_Term)) {
							continue;
						} $attribute_terms[] = ['term_id' => $term->term_id, 'name' => $term->name, 'slug' => $term->slug, 'count' => $term->count];
					}
				} $result[] = ['id' => $tax->attribute_id, 'name' => $tax->attribute_name, 'label' => $tax->attribute_label, 'type' => $tax->attribute_type, 'terms' => $attribute_terms];
			}
		}

return $result;
	}

	public static function getProducts() {
		global $wpdb;
		$query = "
			WITH
			products AS (
				SELECT
					wp_posts.id ,
					wp_posts.post_title ,
					wp_posts.post_name ,
					wp_posts.post_status ,
					wp_posts.post_content ,
					wp_posts.post_excerpt ,
					wp_posts.post_type ,
					wp_posts.post_parent
				FROM
					{$wpdb->posts} AS wp_posts
				WHERE
					wp_posts.post_type IN ('product' , 'product_variation')
			) ,
			meta_fields AS (
				SELECT
					wp_postmeta.post_id , JSON_OBJECTAGG(wp_postmeta.meta_key, wp_postmeta.meta_value) AS meta_fields
				FROM
					{$wpdb->postmeta} AS wp_postmeta
				GROUP BY
					wp_postmeta.post_id
			) ,
			taxonomies (post_id , term_ids) AS (
				SELECT
					wp_term_relationships.object_id , JSON_ARRAYAGG(wp_term_taxonomy.term_id) AS term_ids
				FROM
					{$wpdb->term_relationships} AS wp_term_relationships
				INNER JOIN
					{$wpdb->term_taxonomy} AS wp_term_taxonomy ON wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id
				GROUP BY
					wp_term_relationships.object_id
			)
			SELECT
				products.* , meta_fields.meta_fields , taxonomies.term_ids
			FROM
				products
			INNER JOIN
				meta_fields ON meta_fields.post_id = products.id
			LEFT JOIN
				taxonomies ON taxonomies.post_id = products.id
        ";
		$products = [];
		$allTaxonomies = \ShopManagerPro\Taxonomies\TaxonomyRepository::getTaxonomies();
		$activeCustomFields = CustomFieldDiscoveryService::getActiveCustomFields();
		ACFRepository::getACFFields();
		foreach ($wpdb->get_results($query, ARRAY_A) as $row) {
			try {
				$products[] = self::processProductRow($row, $allTaxonomies, $activeCustomFields);
			} catch (\Throwable $e) {
				Logger::error('Failed to process product row', ['product_id' => $row['id'] ?? 'unknown', 'error' => $e->getMessage()]);
				continue;
			}
		}

return $products;
	}

	private static function processProductRow($row, TaxonomyCollection $allTaxonomies, CustomFieldsCollection $activeCustomFields) {
		$productMetaFields = \ShopManagerPro\Shared\Utils\JSON::decode($row['meta_fields']);
		$imageId = isset($productMetaFields['_thumbnail_id']) ? intval($productMetaFields['_thumbnail_id']) : null;
		$galleryImageIds = [];
		if (isset($productMetaFields['_product_image_gallery'])) {
			$galleryImageIds = array_map('intval', array_filter(explode(',', $productMetaFields['_product_image_gallery'])));
		} $regularPrice = isset($productMetaFields['_price']) && is_numeric($productMetaFields['_price']) ? floatval($productMetaFields['_price']) : null;
		$salePrice = isset($productMetaFields['_sale_price']) && is_numeric($productMetaFields['_sale_price']) ? floatval($productMetaFields['_sale_price']) : null;
		$productBasic = new DTO\Generated\ProductBasic(id: $row['id'], parentId: $row['post_parent'], name: $row['post_title'], descriptionLong: $row['post_content'], descriptionShort: $row['post_excerpt'], imageId: $imageId ?? 0, galleryImageIds: $galleryImageIds, postStatus: DTO\Generated\ProductBasicPostStatus::from($row['post_status']), sku: $productMetaFields['_sku'] ?? '', regularPrice: $regularPrice, salePrice: $salePrice, stock: isset($productMetaFields['_stock']) ? intval($productMetaFields['_stock']) : null, stockStatus: DTO\Generated\ProductBasicStockStatusAlternative1::from($productMetaFields['_stock_status'] ?? 'instock'), taxClass: $productMetaFields['_tax_class'] ?? '', taxStatus: DTO\Generated\ProductBasicTaxStatusAlternative1::from($productMetaFields['_tax_status'] ?? 'taxable'), totalSales: isset($productMetaFields['total_sales']) ? intval($productMetaFields['total_sales']) : 0);
		$termIds = $row['term_ids'] ? \ShopManagerPro\Shared\Utils\JSON::decode($row['term_ids']) : [];
		$splitTaxonomies = self::splitTermsByTaxonomy($termIds, $allTaxonomies);
		$acfCollection = ACFRepository::getACFFields();
		$acfFields = self::getACFFieldsForProducts($acfCollection, $productMetaFields);
		$customAttributes = self::parseCustomMeta($productMetaFields, $activeCustomFields);

		return new DTO\Generated\Product(basic: $productBasic, acf: $acfFields, customMeta: $customAttributes, defaultTaxonomy: $splitTaxonomies[ProductFieldGroupType::DEFAULT_TAXONOMY->value], productAttribute: $splitTaxonomies[ProductFieldGroupType::PRODUCT_ATTRIBUTE->value]);
	}

	private static function getACFFieldsForProducts(ACFCollection $acfCollection, array $productMetaFields) {
		$result = [];
		foreach ($acfCollection->acfFieldsByName as $acfFieldName => $acfField) {
			if (!isset($productMetaFields[$acfFieldName])) {
				continue;
			} $productAcfValue = $productMetaFields[$acfFieldName];
			if (!$productAcfValue) {
				continue;
			} if ($acfField->multiple) {
				$result[$acfField->id] = unserialize($productAcfValue);
			} else {
				$result[$acfField->id] = $productAcfValue;
			}
		}

return $result;
	}

	private static function splitTermsByTaxonomy(array $termIds, TaxonomyCollection $taxonomies) {
		$defaultTaxonomies = [];
		$productAttributes = [];
		foreach ($termIds as $termId) {
			$taxonomy = $taxonomies->taxonomiesByTermId[$termId] ?? null;
			if (!$taxonomy) {
				Logger::error('Term ID not found in taxonomies', ['termId' => $termId]);
				continue;
			} if (ProductFieldRepository::isDefaultTaxonomy($taxonomy->key)) {
				$bucket = &$defaultTaxonomies;
			} elseif (ProductFieldRepository::isProductAttribute($taxonomy->key)) {
				$bucket = &$productAttributes;
			} else {
				Logger::error('Unknown taxonomy type', ['taxonomy' => $taxonomy]);
				continue;
			} if (isset($bucket[$taxonomy->key])) {
				$bucket[$taxonomy->key][] = $termId;
			} else {
				$bucket[$taxonomy->key] = [$termId];
			}
		}

return [ProductFieldGroupType::DEFAULT_TAXONOMY->value => $defaultTaxonomies, ProductFieldGroupType::PRODUCT_ATTRIBUTE->value => $productAttributes];
	}

	private static function parseCustomMeta(array $productMetaFields, CustomFieldsCollection $activeCustomFields) {
		$customMeta = [];
		foreach ($activeCustomFields->byKey as $field) {
			$metaKey = $field->getMetaKey();
			if (!isset($productMetaFields[$metaKey])) {
				continue;
			} $value = $productMetaFields[$metaKey];
			$value = match ($field->getDataType()) {
				CustomFieldsResponseItemsItemConfigDataType::string => (string) $value, CustomFieldsResponseItemsItemConfigDataType::integer => (int) $value, CustomFieldsResponseItemsItemConfigDataType::float => (float) $value, CustomFieldsResponseItemsItemConfigDataType::currency => (float) $value,
			};
			$customMeta[$metaKey] = $value;
		}

return $customMeta;
	}

	public static function updateProduct(\WC_Product $wcProduct, DTO\Generated\Product $updatedProduct) {
		self::updateProductTerms($wcProduct, $updatedProduct);
		self::updateBasicFields($wcProduct, $updatedProduct);
		self::updateCustomMeta($wcProduct, $updatedProduct);
	}

	private static function updateProductTerms(\WC_Product $product, DTO\Generated\Product $updatedProduct) {
		$defaultTaxonomies = $updatedProduct->getDefaultTaxonomy();
		$productAttributes = $updatedProduct->getProductAttribute();
		$allTaxonomies = array_merge($defaultTaxonomies, $productAttributes);
		foreach ($allTaxonomies as $taxonomyName => $termIds) {
			$error = wp_set_object_terms($product->get_id(), $termIds, $taxonomyName);
			if (is_wp_error($error)) {
				throw new \Exception('Failed to set object terms for taxonomy '.$taxonomyName.': '.\ShopManagerPro\Shared\Utils\JSON::encode($error));
			}
		}
	}

	private static function updateBasicFields(\WC_Product $product, DTO\Generated\Product $updatedProduct) {
		$basic = $updatedProduct->getBasic();
		$product->set_description($basic->getDescriptionLong());
		$product->set_gallery_image_ids($basic->getGalleryImageIds());
		$product->set_image_id($basic->getImageId());
		$product->set_name($basic->getName());
		$product->set_regular_price($basic->getRegularPrice());
		$product->set_sale_price($basic->getSalePrice());
		$product->set_short_description($basic->getDescriptionShort());
		$product->set_sku($basic->getSku());
		$product->set_status($basic->getPostStatus()->value);
		$product->set_stock_quantity($basic->getStock());
		$stockStatus = $basic->getStockStatus();
		if (is_string($stockStatus)) {
			$product->set_stock_status($stockStatus);
		} elseif ($stockStatus instanceof DTO\Generated\ProductBasicStockStatusAlternative1) {
			$product->set_stock_status($stockStatus->value);
		} $product->set_tax_class($basic->getTaxClass());
		$taxStatus = $basic->getTaxStatus();
		if (is_string($taxStatus)) {
			$product->set_tax_status($taxStatus);
		} elseif ($taxStatus instanceof DTO\Generated\ProductBasicTaxStatusAlternative1) {
			$product->set_tax_status($taxStatus->value);
		} $product->save();
		if (\ShopManagerPro\Shared\PluginDetectorService::$acfVersion) {
			self::updateACFFields($product, $updatedProduct);
		}
	}

	private static function updateCustomMeta(\WC_Product $product, DTO\Generated\Product $updatedProduct) {
		$productId = $product->get_id();
		foreach ($updatedProduct->getCustomMeta() as $metaKey => $metaValue) {
			update_post_meta($productId, $metaKey, $metaValue);
		}
	}

	private static function updateACFFields(\WC_Product $product, DTO\Generated\Product $updatedProduct) {
		$newAcfFields = ACFRepository::convertByIDtoByKey($updatedProduct->getAcf());
		$postId = $product->get_id();
		$acfCollection = ACFRepository::getACFFields();
		foreach ($newAcfFields as $fieldKey => $fieldValue) {
			$acfField = $acfCollection->acfFieldsByKey[$fieldKey] ?? null;
			if ($acfField && !$acfField->multiple && is_array($fieldValue)) {
				$fieldValue = $fieldValue[0] ?? null;
			} update_field($fieldKey, $fieldValue, $postId);
		}
	}
}
