<?php

namespace PublishPress\FuturePro\Modules\Workflows\Domain\Steps\Actions\Runners;

use PublishPress\Future\Core\HookableInterface;
use PublishPress\Future\Modules\Workflows\Interfaces\StepRunnerInterface;
use PublishPress\Future\Modules\Workflows\Interfaces\StepProcessorInterface;
use PublishPress\Future\Framework\Logger\LoggerInterface;
use PublishPress\Future\Modules\Workflows\Domain\Engine\VariableResolvers\IntegerResolver;
use PublishPress\Future\Modules\Workflows\Domain\Steps\Actions\Definitions\UpdatePostMeta;
use PublishPress\Future\Modules\Workflows\Interfaces\ExecutionContextInterface;

class UpdatePostMetaRunner implements StepRunnerInterface
{
    /**
     * @var HookableInterface
     */
    private $hooks;

    /**
     * @var StepProcessorInterface
     */
    private $stepProcessor;

    /**
     * @var \Closure
     */
    private $expirablePostModelFactory;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var ExecutionContextInterface
     */
    private $executionContext;

    public function __construct(
        HookableInterface $hooks,
        StepProcessorInterface $stepProcessor,
        \Closure $expirablePostModelFactory,
        ExecutionContextInterface $executionContext,
        LoggerInterface $logger
    ) {
        $this->hooks = $hooks;
        $this->stepProcessor = $stepProcessor;
        $this->expirablePostModelFactory = $expirablePostModelFactory;
        $this->executionContext = $executionContext;
        $this->logger = $logger;
    }

    public static function getNodeTypeName(): string
    {
        return UpdatePostMeta::getNodeTypeName();
    }

    public function setup(array $step): void
    {
        $this->stepProcessor->setup($step, [$this, 'actionCallback']);
    }

    private function getMetaIdByMetaKey(int $postId, string $metaKey): int
    {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
        $mid = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT meta_id FROM %i WHERE post_id = %d AND meta_key = %s",
                $wpdb->postmeta,
                $postId,
                $metaKey
            )
        );

        if ($mid !== '') {
            return (int) $mid;
        }

        return 0;
    }

    public function actionCallback(int $postId, array $nodeSettings, array $step)
    {
        $this->stepProcessor->executeSafelyWithErrorHandling(
            $step,
            function ($step, $postId, $nodeSettings) {
                $nodeSlug = $this->stepProcessor->getSlugFromStep($step);

                /** @var ExpirablePostModelInterface $postModel */
                $postModel = call_user_func($this->expirablePostModelFactory, $postId);

                $metaKey = $nodeSettings['metaKey'];
                $metaValue = $this->executionContext->resolveExpressionsInText(
                    $nodeSettings['metaValue']['expression']
                );

                $postModel->updateMeta($metaKey, $metaValue);

                $metaId = $this->getMetaIdByMetaKey($postId, $metaKey);

                $this->executionContext->setVariable($nodeSlug, [
                    'metaId' => new IntegerResolver($metaId),
                ]);
            },
            $postId,
            $nodeSettings
        );
    }
}
