<?php

// phpcs:ignoreFile
namespace DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Factory;

use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Infrastructure\Service\Dependency\Resolver\Abstraction\DependencyResolverInterface;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Exception\ProductTypeException;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductTypes\SingleProductTypesCollection;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductTypes\SingleProductType;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductTypes\SingleProductTypeValidator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Form\Fields\ExportFileTypeFormFields;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\Collection\ProductFieldCollection;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Form\Fields\Component\ProductFieldsComponent;
use DropshippingExportFreeVendor\WPDesk\Forms\Field\CheckboxField;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\ProductField;
use RuntimeException;
use WC_Product;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\DataProvider\AttributeCeneoDataProvider;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\DataProvider\DropshippingDataProvider;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\ProductFieldImgNamePathValue;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\DataProvider\ExportOptionsDataProvider;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Form\Fields\ExportMapperFormFields;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Form\Fields\ExportOptionsFormFields;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\PriceCompare\Config\CeneoConfig;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\PriceCompare\Config\GmcConfig;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\PriceCompare\Config\NokautConfig;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\PriceCompare\PriceCompareAttributeConfig;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\PriceModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\SalePriceModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\StockModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\Value\Modificator\PriceProductFieldModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\Value\Modificator\SalePriceProductFieldModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\Value\Modificator\StockProductFieldModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\PriceCompare\PriceCompareConfig;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\AttributesModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\AvailModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\CategoryModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\CustomAttrProductField;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\ProductFieldCustomStringValue;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\ProductFieldDefaultValue;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\ProductFieldValue;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\Value\Modificator\AttributesProductFieldModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\Value\Modificator\CategoryProductFieldModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\Value\Modificator\CeneoAttributesProductFieldModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\Value\Modificator\CeneoAvailProductFieldModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\Value\Modificator\GmcAvailProductFieldModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ProductFields\Value\Modificator\NokautAvailProductFieldModificator;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Form\Fields\Component\PriceCompareProductFieldsComponent;
class ProductsFactory
{
    private DependencyResolverInterface $resolver;
    private DataProviderFactory $data_provider_factory;
    private ProductFieldsValueFactory $product_fields_value_factory;
    public function __construct(DependencyResolverInterface $dependency_resolver, DataProviderFactory $dp_factory, ProductFieldsValueFactory $product_fields_value_factory)
    {
        $this->resolver = $dependency_resolver;
        $this->data_provider_factory = $dp_factory;
        $this->product_fields_value_factory = $product_fields_value_factory;
    }
    public function create_product_types_collection(array $product_types): SingleProductTypesCollection
    {
        $collection = new SingleProductTypesCollection();
        $validator = new SingleProductTypeValidator(ExportFileTypeFormFields::get_product_types());
        foreach ($product_types as $product_type) {
            $product_type_object = new SingleProductType($product_type);
            if ($validator->is_product_type_valid($product_type_object)) {
                $collection->add_product_type($product_type_object);
            } else {
                throw new ProductTypeException(sprintf('Product type %s is not supported.', $product_type->get_type()));
            }
        }
        return $collection;
    }
    public function create_product_field_collection(string $uid, PriceCompareConfig $config, WC_Product $product): ProductFieldCollection
    {
        $product_mapper_dp = $this->data_provider_factory->create_by_class_name($config->get_mapper_data_provider_class(), ['postfix' => $uid]);
        $product_fields = $product_mapper_dp->get(ProductFieldsComponent::PRODUCT_FIELDS);
        $collection = new ProductFieldCollection();
        foreach ($product_fields as $product_field_row) {
            if ($product_field_row[ProductFieldsComponent::FIELD_ACTIVE] === CheckboxField::VALUE_TRUE) {
                $product_field_value = $product_field_row[ProductFieldsComponent::FIELD_VALUE];
                if ($config->is_custom()) {
                    $product_class = $this->get_product_field_class($product_field_row[ProductFieldsComponent::FIELD_KEY], $config);
                    if (\is_subclass_of($product_class, ProductFieldDefaultValue::class)) {
                        $product_field_class = $product_class::get_default_class_value();
                        $product_field_value = $product_field_class::get_key();
                    }
                }
                $product_value = $this->product_fields_value_factory->get($product, $product_field_value);
                if ($product_value instanceof ProductFieldCustomStringValue) {
                    $product_value->set_string_value($product_field_row[PriceCompareProductFieldsComponent::FIELD_CUSTOM_VALUE] ?? '');
                }
                $product_value = $this->add_modificator($config, $product_value, $product_mapper_dp, $this->data_provider_factory->create_by_class_name(ExportOptionsDataProvider::class, ['postfix' => $uid]));
                $product_field = $this->create_product_field($product_field_row[ProductFieldsComponent::FIELD_KEY], $config, $product_value);
                if ($config->is_custom()) {
                    $product_field->set_field_name($product_field_row[ProductFieldsComponent::FIELD_VALUE]);
                    if ($product_field instanceof CustomAttrProductField) {
                        if ($product_mapper_dp->has(ExportMapperFormFields::PRODUCT_ATTRIBUTES_AS_SINGLE_VALUE)) {
                            $is_multiple = $product_mapper_dp->get(ExportMapperFormFields::PRODUCT_ATTRIBUTES_AS_SINGLE_VALUE) !== CheckboxField::VALUE_TRUE;
                            $product_field->set_as_multiple_column($is_multiple);
                        }
                    }
                }
                $collection->add_product_field($product_field);
            }
        }
        return $collection;
    }
    private function add_modificator(PriceCompareConfig $config, ProductFieldValue $product_field_value, DropshippingDataProvider $product_mapper_dp, ExportOptionsDataProvider $options_dp): ProductFieldValue
    {
        if ($product_field_value instanceof CategoryModificator) {
            $dependency = $this->resolver->resolve(CategoryProductFieldModificator::class, ['data_provider' => $product_mapper_dp, 'price_compare_config' => $config]);
            $product_field_value->set_category_modificator($dependency);
        }
        if ($product_field_value instanceof AttributesModificator) {
            if ($config instanceof PriceCompareAttributeConfig && CeneoConfig::ID === $config->get_id()) {
                $settings_dp = $this->data_provider_factory->create_by_class_name(AttributeCeneoDataProvider::class);
                $dependency = $this->resolver->resolve(CeneoAttributesProductFieldModificator::class, ['data_provider' => $product_mapper_dp, 'settings_data_provider' => $settings_dp]);
                $product_field_value->set_attributes_modificator($dependency);
            } elseif ($config->is_custom()) {
                $dependency = $this->resolver->resolve(AttributesProductFieldModificator::class, ['data_provider' => $product_mapper_dp]);
                $product_field_value->set_attributes_modificator($dependency);
            }
        }
        if ($product_field_value instanceof PriceModificator) {
            $dependency = $this->resolver->resolve(PriceProductFieldModificator::class, ['data_provider' => $product_mapper_dp]);
            $product_field_value->set_price_modificator($dependency);
        }
        if ($product_field_value instanceof StockModificator) {
            $dependency = $this->resolver->resolve(StockProductFieldModificator::class, ['data_provider' => $product_mapper_dp]);
            $product_field_value->set_stock_modificator($dependency);
        }
        if ($product_field_value instanceof AvailModificator) {
            $class = $this->get_avail_modificator_class($config->get_id());
            if (\is_string($class)) {
                $dependency = $this->resolver->resolve($class);
                $product_field_value->set_avail_modificator($dependency);
            }
        }
        if ($product_field_value instanceof ProductFieldImgNamePathValue) {
            $only_image_name = $options_dp->has(ExportOptionsFormFields::SAVE_IMAGES_AS_ZIP) && $options_dp->get(ExportOptionsFormFields::SAVE_IMAGES_AS_ZIP) === CheckboxField::VALUE_TRUE;
            $product_field_value->set_only_image_name($only_image_name);
        }
        return $product_field_value;
    }
    private function get_avail_modificator_class(string $price_config_key): ?string
    {
        $config = [CeneoConfig::ID => CeneoAvailProductFieldModificator::class, NokautConfig::ID => NokautAvailProductFieldModificator::class, GmcConfig::ID => GmcAvailProductFieldModificator::class];
        if (isset($config[$price_config_key])) {
            return $config[$price_config_key];
        }
        return null;
    }
    private function create_product_field(string $name, PriceCompareConfig $config, ProductFieldValue $product_value): ProductField
    {
        $fields = $config->get_supported_fields();
        foreach ($fields as $field) {
            if ($name === $field::get_default_field_name()) {
                return $this->resolver->resolve($field, ['product_value' => $product_value]);
            }
        }
        throw new RuntimeException('Product field ' . $name . ' not exists');
    }
    private function get_product_field_class(string $name, PriceCompareConfig $config): string
    {
        $fields = $config->get_supported_fields();
        foreach ($fields as $field) {
            if ($name === $field::get_default_field_name()) {
                return $field;
            }
        }
        throw new RuntimeException('Product field ' . $name . ' not exists');
    }
}
