<?php declare(strict_types = 1);

namespace idoit\Module\SyneticsFlows\Automation\Action\PerformExecution;

use idoit\Module\SyneticsFlows\Automation\Action\ExecutionInfo\UpdateDataInfo;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionResult\ErrorExecutionResult;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionResult\ExecutionResult;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionResult\UpdateDataResult;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionResult\ValidationError;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionResult\ValidationErrorResult;
use idoit\Module\SyneticsFlows\Automation\Execution;
use Throwable;

class UpdateDataExecution implements PerformExecution
{
    public function __construct(private ApplyCategoryChanges $applyCategoryChanges, private ValidateCategoryChanges $validateCategoryChanges)
    {
    }

    /**
     * @param Execution $execution
     *
     * @return ExecutionResult
     */
    public function perform(Execution $execution): ExecutionResult
    {
        $parameters = $execution->getExecution();
        if (!$parameters instanceof UpdateDataInfo) {
            return new ErrorExecutionResult('Unsupported execution');
        }

        try {
            $objectIds = $parameters->getObjectIds();
            $changes = $parameters->getChanges();
            $validationErrors = [];

            // Validate all data beforehand for each object
            foreach ($objectIds as $objectId) {
                $objectId = (int)$objectId;
                foreach ($changes as $change) {
                    $errors = $this->validateCategoryChanges->validateChange($objectId, $change);

                    if (is_array($errors)) {
                        foreach ($errors as $field => $error) {
                            $validationErrors[] = new ValidationError($change->getCategoryId(), $field, $error, "$objectId");
                        }
                    }
                }
            }

            if (!empty($validationErrors)) {
                return new ValidationErrorResult($validationErrors);
            }

            foreach ($objectIds as $objectId) {
                $objectId = (int)$objectId;
                foreach ($changes as $change) {
                    $this->applyCategoryChanges->applyChange($objectId, $change);
                }
            }

            return new UpdateDataResult($objectIds, $changes);
        } catch (Throwable $e) {
            return new ErrorExecutionResult("Something went wrong while syncing data: {$e->getMessage()}");
        }
    }

    public function supports(Execution $execution): bool
    {
        return $execution->getExecution() instanceof UpdateDataInfo;
    }
}
