<?php

namespace CouponsPlus\App\Conditions\Utilities;

use CouponsPlus\App\Compatibility\Wpml\CurrentLanguageIdGetter;
use CouponsPlus\App\Compatibility\Wpml\OriginalIdGetter;
use CouponsPlus\App\Compatibility\Wpml\TranslationIds;
use CouponsPlus\App\Compatibility\Wpml\TranslationIdsOnlyWhenCurrentLanguageIsForeign;
use CouponsPlus\App\Compatibility\Wpml\TranslationIdsOnlyWhenSitePressIsAvailable;
use CouponsPlus\App\Compatibility\Wpml\TranslationIdsSameWhenEmpty;
use CouponsPlus\Original\Characters\StringManager;
use CouponsPlus\Original\Collections\Collection;
use WC_Product;
use WC_Product_Variation;

class ProductUtilities
{
    /**
     * @var \WC_Product $product
     */
    protected $product;
    /**
     * @var BasicDataObjectTypes $product
     */
    protected $basicDataObjectTypes;
    public function __construct(\WC_Product $product)
    {
        $this->product = $product;
        $this->basicDataObjectTypes = new BasicDataObjectTypes;
    } 

    public function getFor(WC_Product $product) : self
    {
        return new static($product);
    }

    /**
     * Raw product = the WC_Product we have in: $this->product(could be a child, translated product)
     */
    public function getCurrentProduct() : WC_Product
    {
        return $this->product;
    }

    /**
     * Raw Final product = the WC_Product or WC_Product_Variation we have in: $this->product (could be a child, translated product)
     */
    public function getCurrentFinalProduct() : WC_Product/*|WC_Product_Variation*/
    {
        return $this->getProductOrProductVariation($this->getCurrentProduct());
    }

    /**
     * Original product = the WC_Product OF THE PRODUCT FROM THE ORIGINAL LANGUAGE
     */
    public function getOriginalProduct() : WC_Product
    {
        (object) $translationIds = new TranslationIdsSameWhenEmpty(
            new TranslationIdsOnlyWhenSitePressIsAvailable(
                new TranslationIdsOnlyWhenCurrentLanguageIsForeign(
                    new OriginalIdGetter('post_product')
                )
            )
        );

        (object) $originalId = $translationIds->get($this->product->get_id($context = 'edit'));

        if ($originalId->first() === $this->product->get_id()) {
            return $this->product;
        }

        return wc_get_product($originalId->first()) ?: $this->product;
    }

    /**
     * Original Final product = the WC_Product or WC_Product_Variation OF THE PRODUCT FROM THE ORIGINAL LANGUAGE
     */
    public function getOrignalFinalProduct() : WC_Product/*|WC_Product_Variation*/
    {
        return $this->getProductOrProductVariation($this->getOriginalProduct());
    }

    /**
     * Original product = the WC_Product OF THE PRODUCT FROM THE ORIGINAL LANGUAGE
     */
    public function getProductForCurrentLanguage() : WC_Product
    {
        (object) $translationIds = new TranslationIdsSameWhenEmpty(
            new TranslationIdsOnlyWhenSitePressIsAvailable(
                new TranslationIdsOnlyWhenCurrentLanguageIsForeign(
                    new CurrentLanguageIdGetter('post_product')
                )
            )
        );

        (object) $originalId = $translationIds->get($this->product->get_id($context = 'edit'));

        return wc_get_product($originalId->first()) ?: $this->product;
    }

    protected function getProductOrProductVariation(WC_Product $product) : WC_Product/*|WC_Product_Variation*/
    {
        if ($product->get_type() === 'variation') {
            return wc_get_product($product->get_parent_id($context = 'edit')) ?: $product;
        } 

        return $product;
    }

    public function getCategoryIds() : Collection
    {
        return new Collection($this->product->get_category_ids($context = 'edit'));
    }

    public function getTagIds() : Collection
    {
        return new Collection($this->product->get_tag_ids($context = 'edit'));
    }

	public function getBrandIds() : Collection
	{
		return new Collection(wp_get_post_terms($this->product->get_id(), 'product_brand', array( 'fields' => 'ids' ) ));
	}

	public function getCategoryIdsWithAncestors(Collection $categoryIds = null) : Collection
    {
        return $this->getTaxonomyIdsWithAncestors($categoryOrTag = 'category', $categoryIds);
    }

    public function getTagIdsWithAncestors(Collection $categoryIds = null) : Collection
    {
        return $this->getTaxonomyIdsWithAncestors($categoryOrTag = 'tag', $categoryIds);
    }

    public function getTaxonomyIdsWithAncestors(string $categoryOrTag, Collection $categoryIds = null) : Collection
    {
        (string) $getCategoryOrTagIds = "get{$categoryOrTag}Ids";
	    (object) $categoryOrTag = StringManager::create($categoryOrTag);
		$taxonomyIdentifiers = new Collection([
			'category' => 'product_cat',
			'tag' => 'product_tag',
			'brand' => 'product_brand',
		]);
        (string) $wooCommerceType = $taxonomyIdentifiers->get($categoryOrTag);

        (object) $categoryIds = $categoryIds ?? $this->{$getCategoryOrTagIds}();

        foreach ($categoryIds->asArray() as $categoryId) {
            $categoryIds->append(get_ancestors($categoryId, $wooCommerceType));
        }   

        return $categoryIds;
    }

    public function getAllTranslationCategoryIds() : Collection
    {
        return $this->getAllTranslationTaxonomyIds('category');
    }

    public function getAllTranslationTagIds() : Collection
    {
        return $this->getAllTranslationTaxonomyIds('tag');
    }

    public function getAllTranslationTaxonomyIds(string $categoryOrTag) : Collection
    {
        (string) $getCategoryOrTagIds = "get{$categoryOrTag}Ids";
        (string) $wooCommerceType = StringManager::create($categoryOrTag)->is('category', $caseinsensitive = true)? 'product_cat' : 'product_tag';

        global $sitepress;

        if (!is_object($sitepress) || $sitepress->get_default_language() === $sitepress->get_current_language()) {
            return $this->{$getCategoryOrTagIds}();
        }

        (object) $translationCategoryIdsGetter = new TranslationIdsOnlyWhenSitePressIsAvailable(
            new TranslationIdsOnlyWhenCurrentLanguageIsForeign(
                new TranslationIds("tax_{$wooCommerceType}")
            )
        );
        (object) $withOriginalCategories = new Collection($this->{$getCategoryOrTagIds}());

        foreach ($this->{$getCategoryOrTagIds}()->asArray() as $categoryId) {
            $withOriginalCategories->append(
                $translationCategoryIdsGetter->get($categoryId)
            );
        }

        return $withOriginalCategories;
    }

    public function getAllTranslationCategoryIdsWithAncestors() : Collection
    {
        return $this->getAllTranslationTaxonomyIdsWithAncestors('category');
    }

    public function getAllTranslationTagsIdsWithAncestors() : Collection
    {
        return $this->getAllTranslationTaxonomyIdsWithAncestors('tag');
    }

    public function getAllTranslationBrandIdsWithAncestors() : Collection
    {
        return $this->getAllTranslationTaxonomyIdsWithAncestors('brand');
    }

    public function getAllTranslationTaxonomyIdsWithAncestors(string $categoryOrTag) : Collection
    {
        return $this->getTaxonomyIdsWithAncestors(
            $categoryOrTag,
            $categoryIds = $this->getAllTranslationTaxonomyIds($categoryOrTag)
        );
    }
}