<?php

namespace DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Factory;

use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Infrastructure\Service\Dependency\Resolver\Abstraction\DependencyResolverInterface;
use RuntimeException;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ConditionalLogic\Conditions\Abstraction\Condition;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Form\Fields\Component\ConditionalLogicComponent;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ConditionalLogic\SingleConditionalLogic;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ConditionalLogic\Fields\Abstraction\Field;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ConditionalLogic\Conditions\Abstraction\ConditionWithValue;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\ConditionalLogic\ConditionalLogicCollection;
/**
 * Class ConditionalLogicFactory, factory for conditional logic.
 *
 * @package WPDesk\Library\DropshippingExport\Factory
 */
class ConditionalLogicFactory
{
    /**
     * @var DependencyResolverInterface
     */
    private $resolver;
    public function __construct(DependencyResolverInterface $dependency_resolver)
    {
        $this->resolver = $dependency_resolver;
    }
    public function create_conditional_logic_collection(array $conditions): ConditionalLogicCollection
    {
        $collection = new ConditionalLogicCollection();
        $conditions = $this->convert_conditions_array($conditions);
        foreach ($conditions as $condition) {
            $single_condition = $this->create_single_condition($condition);
            $collection->add_condition($single_condition);
        }
        return $collection;
    }
    private function create_single_condition(array $condition): SingleConditionalLogic
    {
        $field = $this->get_field($condition[ConditionalLogicComponent::FIELD_TYPE]);
        $raw_value = isset($condition[ConditionalLogicComponent::FIELD_VALUE]) ? $condition[ConditionalLogicComponent::FIELD_VALUE] : '';
        $field_value = '';
        if (is_array($raw_value)) {
            $field_value = implode('|', array_map('strval', $raw_value));
        } else {
            $field_value = strval($raw_value);
        }
        $single_condition = $this->get_condition($condition[ConditionalLogicComponent::FIELD_VALUE_TYPE], $field_value);
        return $this->resolver->resolve(SingleConditionalLogic::class, ['field' => $field, 'condition' => $single_condition]);
    }
    private function get_field(string $field_name): Field
    {
        $fields_classes = ConditionalLogicComponent::get_product_fields();
        foreach ($fields_classes as $class) {
            if ($class::get_name() === $field_name) {
                $field = $this->resolver->resolve($class);
                return is_object($field) ? clone $field : $field;
            }
        }
        throw new RuntimeException(sprintf('Field name %s is not defined', $field_name));
    }
    private function get_condition(string $field_type, string $field_value): Condition
    {
        $fields_classes = ConditionalLogicComponent::get_supported_value_types();
        foreach ($fields_classes as $class) {
            if ($class::get_name() === $field_type) {
                $condition = $this->resolver->resolve($class);
                $condition = is_object($condition) ? clone $condition : $condition;
                if ($condition instanceof ConditionWithValue) {
                    $condition->set_value($field_value);
                }
                return $condition;
            }
        }
        throw new RuntimeException(sprintf('Field type %s is not defined', $field_type));
    }
    public function create_by_name(string $field_type): Condition
    {
        $fields_classes = ConditionalLogicComponent::get_supported_value_types();
        foreach ($fields_classes as $class) {
            if ($class::get_name() === $field_type) {
                $condition = $this->resolver->resolve($class);
                $condition = is_object($condition) ? clone $condition : $condition;
                return $condition;
            }
        }
        throw new RuntimeException(sprintf('Field type %s is not defined', $field_type));
    }
    private function convert_conditions_array(array $conditions): array
    {
        $result = [];
        if (isset($conditions[ConditionalLogicComponent::FIELD_TYPE])) {
            foreach ($conditions[ConditionalLogicComponent::FIELD_TYPE] as $key => $type) {
                if (isset($conditions[ConditionalLogicComponent::FIELD_VALUE_TYPE][$key])) {
                    $value_type = $conditions[ConditionalLogicComponent::FIELD_VALUE_TYPE][$key];
                    if (isset($conditions[$value_type][$key])) {
                        $value = $conditions[$value_type][$key];
                        $result[] = [ConditionalLogicComponent::FIELD_TYPE => $type, ConditionalLogicComponent::FIELD_VALUE_TYPE => $value_type, ConditionalLogicComponent::FIELD_VALUE => $value];
                    } else {
                        $result[] = [ConditionalLogicComponent::FIELD_TYPE => $type, ConditionalLogicComponent::FIELD_VALUE_TYPE => $value_type];
                    }
                }
            }
        }
        return $result;
    }
}
