<?php

namespace DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\Value\Modificator;

use Exception;
use WC_Product;
use WC_Product_Attribute;
use WC_Product_Variation;
use WC_Product_Factory;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\ProductFieldValueModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\DataProvider\DropshippingDataProvider;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Form\Fields\ExportMapperFormFields;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\ProductFieldArrayValue;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\ProductFieldStringValue;
class AttributesProductFieldModificator implements ProductFieldValueModificator, ProductFieldArrayValue, ProductFieldStringValue
{
    public const OPTIONS_SEPARATOR = ',';
    public const KEY_SEPARATOR = ':';
    public const ATTRIBUTES_SEPARATOR = '; ';
    private bool $is_select_none;
    private array $attributes_selector;
    private WC_Product_Factory $wc_factory;
    private DropshippingDataProvider $data_provider;
    private WC_Product $product;
    public function __construct(WC_Product_Factory $wc_factory, DropshippingDataProvider $data_provider)
    {
        $this->wc_factory = $wc_factory;
        $this->data_provider = $data_provider;
    }
    public function set_product(WC_Product $product): void
    {
        $this->product = $product;
    }
    public function has_array_value(): bool
    {
        return \is_array($this->get_array_value());
    }
    public function get_array_value(): ?array
    {
        $attributes = ExportMapperFormFields::get_woo_attributes();
        $result = $this->get_allowed_attributes($attributes);
        return array_flip($result);
    }
    public function has_string_value(): bool
    {
        return \is_string($this->get_string_value());
    }
    public function get_string_value(): ?string
    {
        if ($this->product instanceof WC_Product_Variation) {
            $attributes = $this->get_variation_attributes_as_string($this->product);
        } else {
            $attributes = $this->get_simple_attributes_as_string($this->product);
        }
        return $attributes;
    }
    private function get_variation_attributes_as_string(WC_Product $product): string
    {
        $result = '';
        $tmp_array = [];
        $variation_attributes = $this->get_attributes($product);
        $parent = $this->wc_factory->get_product($product->get_parent_id());
        $parent_attributes = $this->get_attributes($parent);
        foreach ($variation_attributes as $key => $value) {
            if (isset($parent_attributes[$key])) {
                $string = $this->get_attribute_as_string($parent_attributes[$key], $value);
                if (!empty($string)) {
                    $tmp_array[] = $string;
                }
            }
        }
        if (!empty($tmp_array)) {
            $result = \implode(self::ATTRIBUTES_SEPARATOR, $tmp_array);
        }
        return $result;
    }
    private function get_simple_attributes_as_string(WC_Product $product): string
    {
        $result = '';
        $tmp_array = [];
        $attributes = $this->get_attributes($product);
        /**
         * @var WC_Product_Attribute $attribute
         */
        foreach ($attributes as $attribute) {
            $string = $this->get_attribute_as_string($attribute);
            if (!empty($string)) {
                $tmp_array[] = $string;
            }
        }
        if (!empty($tmp_array)) {
            $result = \implode(self::ATTRIBUTES_SEPARATOR, $tmp_array);
        }
        return $result;
    }
    private function get_attribute_as_string(WC_Product_Attribute $attribute, string $search_value = ''): string
    {
        $result = '';
        $attribute = $this->get_attribute($attribute);
        if (\is_array($attribute) && !empty($attribute)) {
            foreach ($attribute as $attribute_name => $options) {
                if (strlen($search_value) > 0 && \in_array($search_value, $options)) {
                    $options = [$search_value];
                }
                return $attribute_name . self::KEY_SEPARATOR . ' ' . implode(self::OPTIONS_SEPARATOR, $options);
            }
        }
        return $result;
    }
    private function get_attribute(WC_Product_Attribute $attribute): array
    {
        $result = [];
        $id = $attribute->get_id();
        if (!empty($id)) {
            $taxonomy = $attribute->get_taxonomy_object();
            if (\is_object($taxonomy)) {
                $name = $taxonomy->attribute_label;
                if (empty($name)) {
                    return $result;
                }
                $options = $attribute->get_options();
                $options = \array_map(function ($v) use ($attribute) {
                    $term = \get_term($v, $attribute->get_name());
                    return $term->name;
                }, $options);
                $result[$name] = $options;
            }
        }
        return $result;
    }
    private function get_attributes(WC_Product $product)
    {
        $attributes = $product->get_attributes();
        if ($product->is_type('variation') && !empty($attributes)) {
            $old_attributes = $attributes;
            $attributes = [];
            foreach ($old_attributes as $meta_key => $meta) {
                $attributes[$meta_key] = $product->get_attribute($meta_key);
            }
        }
        return $this->get_allowed_attributes($attributes);
    }
    private function get_allowed_attributes(array $attributes): array
    {
        $attributes_selector = $this->get_attributes_selector();
        $is_none_option = $this->is_select_none_option();
        foreach ($attributes as $key => $val) {
            if (\in_array($key, $attributes_selector)) {
                if (!$is_none_option) {
                    unset($attributes[$key]);
                }
            } elseif ($is_none_option) {
                unset($attributes[$key]);
            }
        }
        return $attributes;
    }
    private function is_select_none_option(): bool
    {
        if (isset($this->is_select_none)) {
            return $this->is_select_none;
        }
        $attributes_type = $this->data_provider->has(ExportMapperFormFields::PRODUCT_ATTRIBUTES_SELECT) ? $this->data_provider->get(ExportMapperFormFields::PRODUCT_ATTRIBUTES_SELECT) : '';
        $this->is_select_none = $attributes_type === ExportMapperFormFields::PRODUCT_ATTRIBUTES_SELECT_VALUE_NONE;
        return $this->is_select_none;
    }
    private function get_attributes_selector(): array
    {
        if (isset($this->attributes_selector)) {
            return $this->attributes_selector;
        }
        $this->attributes_selector = $this->data_provider->has(ExportMapperFormFields::PRODUCT_ATTRIBUTES_VALUES) ? $this->data_provider->get(ExportMapperFormFields::PRODUCT_ATTRIBUTES_VALUES) : [];
        return $this->attributes_selector;
    }
}
