<?php

namespace Easymailing\App\Core\Provider\Woocommerce\Batch;


use Easymailing\App\Core\Log\LogManager;
use Easymailing\App\Core\Provider\Woocommerce\Model\BatchOperationIdentifier;
use Easymailing\App\Core\Provider\Woocommerce\Model\LogType;
use Easymailing\App\Core\Provider\Woocommerce\Model\SynchronizationStatus;
use Easymailing\App\Core\Provider\Woocommerce\Service\MetadataHelper;
use Easymailing\App\Repository\ConfigRepository;
use Easymailing\App\Utils\Api;


class ProductBatchOperations
{
	private $configRepository;
	private $logManager;

	private $shopId;

	public function __construct(ConfigRepository $configRepository,  LogManager $logManager)
	{
		$this->configRepository = $configRepository;
		$this->logManager = $logManager;
	}

    public function getProductBatchOperations(): array
    {
        $batchOperations = [];
        try {
			$this->logManager->createLog(LogType::BATCH, "Start ProductBatchOperations");
			$this->shopId = $this->configRepository->getSynchronizationConfig()->getShopId();

            $args = ['limit' => -1];
            $wpProducts = wc_get_products($args);
            $retryOnly = (bool) get_option(MetadataHelper::getRetryOnlyMode());

            foreach ($wpProducts as $product) {
                if ($retryOnly && $this->isNotInError((int) $product->get_id())) {
                    continue;
                }
                $batchOperations[] = $this->processProduct($product);
            }

        } catch (\Exception $e) {
			$this->logManager->createLog(LogType::BATCH, sprintf("Error in ProductBatchOperations: %s", $e->getMessage()));
        }

		$this->logManager->createLog(LogType::BATCH, "End ProductBatchOperations");
	    return $batchOperations;
    }

    public function getVariantBatchOperations(): array
    {
        $batchOperations = [];
        try {
            $this->logManager->createLog(LogType::BATCH, "Start VariantBatchOperations");
            $this->shopId = $this->configRepository->getSynchronizationConfig()->getShopId();

            $args = ['limit' => -1];
            $wpProducts = wc_get_products($args);
            $retryOnly = (bool) get_option(MetadataHelper::getRetryOnlyMode());

            foreach ($wpProducts as $product) {
                $productResourceId = get_post_meta($product->get_id(), MetadataHelper::getResourceId(), true);

                // Sin producto creado en Easymailing no podemos mandar sus variantes.
                // El meta se escribe en la fase de productos (antes de esta fase) o se
                // limpia por auto-recovery si el POST falló; en ambos casos saltamos.
                if (empty($productResourceId)) {
                    continue;
                }

                $batchOperations = array_merge($batchOperations, $this->processVariations($product, $productResourceId, $retryOnly));
            }

        } catch (\Exception $e) {
            $this->logManager->createLog(LogType::BATCH, sprintf("Error in VariantBatchOperations: %s", $e->getMessage()));
        }

        $this->logManager->createLog(LogType::BATCH, "End VariantBatchOperations");
        return $batchOperations;
    }

    private function isNotInError(int $postId): bool
    {
        return get_post_meta($postId, MetadataHelper::getSynchronizationStatus(), true) !== SynchronizationStatus::ERROR;
    }

    private function processProduct(\WC_Product $product): array
    {
        $productId = $product->get_id();
        $productResourceId = get_post_meta($productId, MetadataHelper::getResourceId(), true);

        if (!$productResourceId) {
            $productResourceId = wp_generate_uuid4();
            return $this->createProductLine($product, $productResourceId);
        }

        return $this->updateProductLine($product, $productResourceId);
    }

    private function createProductLine(\WC_Product$product, string $productResourceId): array
    {
        return $this->buildProductLine($product, $productResourceId, 'POST');
    }

    private function updateProductLine(\WC_Product$product, string $productResourceId): array
    {
        return $this->buildProductLine($product, $productResourceId, 'PUT');
    }

    private function buildProductLine(\WC_Product $product, string $productResourceId, string $method): array
    {
        $url = "/stores/".$this->shopId."/products" . ($method === 'PUT' ? "/$productResourceId" : '');

        $imageId = $product->get_image_id();
        $imageUrl = $imageId ? wp_get_attachment_image_url($imageId, 'full') : null;

        $brands = wp_get_post_terms($product->get_id(), 'product_brand', ['fields' => 'names']);
        $vendor = (!is_wp_error($brands) && !empty($brands)) ? $brands[0] : null;

        $body = [
            'resource_id' => $productResourceId,
            'title' => $product->get_name(),
            'description' => $product->get_description(),
            'url' => get_permalink($product->get_id()),
            'vendor' => $vendor,
            'image_url' => is_string($imageUrl) ? $imageUrl : null,
            'categories' => $this->getCategoryResourceIds($product->get_id()),
        ];

		update_post_meta($product->get_id(), MetadataHelper::getResourceId(), $productResourceId);

        return [
			"method" => $method,
			"path" => $url,
			"body" => json_encode($body),
			"external_identifier" => BatchOperationIdentifier::buildIdentifier(BatchOperationIdentifier::PRODUCT, $product->get_id())
        ];
    }

    private function processVariations(\WC_Product $product, string $productResourceId, bool $retryOnly = false): array
    {
        $batchOperations = [];

        if ($product->is_type('variable')) {
            $variations = $product->get_available_variations();
            foreach ($variations as $variation) {
                if ($retryOnly && $this->isNotInError((int) $variation['variation_id'])) {
                    continue;
                }
                $batchOperations[] = $this->processVariation($variation, $productResourceId);
            }
        } else {
            // Para variantes simples compartimos post con el product. Si el product
            // ya sincronizó bien pero la operación de variant_simple falló, el status
            // del post quedaría en error, así que el filtro funciona igual.
            if ($retryOnly && $this->isNotInError((int) $product->get_id())) {
                return $batchOperations;
            }
            $batchOperations[] = $this->processSimpleProductVariation($product, $productResourceId);
        }

        return $batchOperations;
    }

    private function processVariation(array $variation, string $productResourceId): array
    {
	    $variationResourceId = get_post_meta($variation['variation_id'], MetadataHelper::getResourceId(), true);
        if ($variationResourceId) {
            return $this->updateEasyMailingVariationLine($variationResourceId, $productResourceId, $variation);
        } else {
            return $this->createEasyMailingVariationLine($variation, $productResourceId);
        }
    }

    private function processSimpleProductVariation(\WC_Product $product, string $productResourceId): array
    {
        $variationResourceId = get_post_meta($product->get_id(), MetadataHelper::getVariantResourceId(), true);
        if ($variationResourceId) {
            return $this->updateEasyMailingSimpleProductVariationLine($variationResourceId, $productResourceId, $product);
        } else {
            return $this->createEasyMailingSimpleProductVariationLine($productResourceId, $product);
        }
    }

    private function createEasyMailingVariationLine(array $variation, string $productResourceId): array
    {
        return $this->buildVariationLine($variation, $productResourceId, 'POST');
    }

    private function updateEasyMailingVariationLine(string $variationResourceId, string $productResourceId, array $variation): array
    {
        return $this->buildVariationLine($variation, $productResourceId, 'PUT', $variationResourceId);
    }

    private function buildVariationLine(array $variation, string $productResourceId, string $method, ?string $variationResourceId = null): array
    {
	    $shopId = $this->shopId;
        $url = "/stores/$shopId/products/$productResourceId/variants" . ($method === 'PUT' ? "/$variationResourceId" : '');

		if(!$variationResourceId){
			$variationResourceId = wp_generate_uuid4();
		}
        $body = [
            'resource_id' => $variationResourceId,
            'title' => get_the_title($variation['variation_id']),
            'sku' => $variation['sku'],
            'price' => Api::convertEurToCents($variation['display_price']),
            'inventory_quantity' => intval($variation["max_qty"]),
            'url' => get_permalink($variation['variation_id']),
            'image_url' => !empty($variation['image']['url']) ? $variation['image']['url'] : null,
        ];

		update_post_meta($variation['variation_id'], MetadataHelper::getResourceId(), $variationResourceId);

        return [
			"method" => $method,
			"path" => $url,
			"body" => json_encode($body),
			"external_identifier" => BatchOperationIdentifier::buildIdentifier(BatchOperationIdentifier::VARIANT, $variation['variation_id'])
        ];
    }

    private function createEasyMailingSimpleProductVariationLine(string $productResourceId, \WC_Product $product): array
    {
        return $this->buildSimpleProductVariationLine($product, $productResourceId, 'POST');
    }

    private function updateEasyMailingSimpleProductVariationLine(string $variationResourceId, string $productResourceId, \WC_Product $product): array
    {
        return $this->buildSimpleProductVariationLine($product, $productResourceId, 'PUT', $variationResourceId);
    }

    private function buildSimpleProductVariationLine(\WC_Product $product, string $productResourceId, string $method, ?string $variationResourceId = null): array
    {
	    $shopId = $this->shopId;
        $url = "/stores/$shopId/products/$productResourceId/variants" . ($method === 'PUT' ? "/$variationResourceId" : '');
        $imageId = $product->get_image_id();
        $imageUrl = $imageId ? wp_get_attachment_image_url($imageId, 'full') : null;
	    if(!$variationResourceId){
		    $variationResourceId = wp_generate_uuid4();
	    }
        $body = [
            'resource_id' => $variationResourceId,
            'title' => $product->get_name(),
            'sku' => $product->get_sku(),
            'price' => Api::convertEurToCents($product->get_regular_price()),
            'inventory_quantity' => intval($product->get_stock_quantity()),
            'url' => $product->get_permalink(),
            'image_url' => is_string($imageUrl) ? $imageUrl : null,
        ];

		update_post_meta($product->get_id(), MetadataHelper::getVariantResourceId(), $variationResourceId);

        return [
			"method" => $method,
			"path" => $url,
			"body" => json_encode($body),
			"external_identifier" => BatchOperationIdentifier::buildIdentifier(BatchOperationIdentifier::VARIANT_SIMPLE, $product->get_id())
        ];
    }

	private function getCategoryResourceIds(int $postId): array
	{
		$shopId = $this->shopId;
		$wpProductCategories = get_the_terms($postId, 'product_cat');

		if (is_wp_error($wpProductCategories) || empty($wpProductCategories)) {
			return [];
		}

		$iris = array_map(
			function ($category) use ($shopId) {
				$resourceId = get_term_meta($category->term_id, MetadataHelper::getResourceId(), true);
				if (empty($resourceId)) {
					return null;
				}
				return "/stores/" . $shopId . "/categories/" . $resourceId;
			},
			$wpProductCategories
		);

		return array_values(array_filter($iris));
	}
}
