<?php

/*
 * This file is part of Chevere.
 *
 * (c) Rodolfo Berrios <rodolfo@chevere.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

declare(strict_types=1);

namespace Chevere\Workflow;

use Chevere\Action\Interfaces\ActionInterface;
use Chevere\Workflow\Interfaces\JobInterface;
use Chevere\Workflow\Interfaces\ResponseReferenceInterface;
use Chevere\Workflow\Interfaces\RunInterface;
use Chevere\Workflow\Interfaces\RunnerInterface;
use Chevere\Workflow\Interfaces\VariableInterface;
use Chevere\Workflow\Interfaces\WorkflowInterface;
use Throwable;

// @codeCoverageIgnoreStart

/**
 * Creates a WorkflowInterface instance for the given jobs.
 *
 * workflow(
 *     job1: sync|async(
 *        new MyAction(),
 *        foo: $foo, <variable|reference|raw>
 *     ),
 * )
 */
function workflow(JobInterface ...$job): WorkflowInterface
{
    return new Workflow(
        new Jobs(...$job)
    );
}

/**
 * Creates a synchronous job for the given action and arguments.
 *
 * @param ActionInterface $_ The action to run
 * @param mixed ...$argument Action arguments for its run method (raw, reference or variable)
 */
function sync(ActionInterface $_, mixed ...$argument): JobInterface
{
    return (new Job($_, ...$argument))
        ->withIsSync(true);
}

/**
 * Creates an asynchronous job for the given action and arguments.
 *
 * @param ActionInterface $_ The action to run
 * @param mixed ...$argument Action arguments for its run method (raw, reference or variable)
 */
function async(ActionInterface $_, mixed ...$argument): JobInterface
{
    return new Job($_, ...$argument);
}

/**
 * Creates a reference to the response for the given job and key (if any).
 *
 * @param string $job Job
 * @param ?string $key Job response key (optional)
 */
function response(string $job, ?string $key = null): ResponseReferenceInterface
{
    return new ResponseReference($job, $key);
}

/**
 * Creates a workflow variable.
 *
 * @param string $name Variable name
 */
function variable(string $name): VariableInterface
{
    return new Variable($name);
}

/**
 * Creates a RunnerInterface instance for the given job.
 */
function runnerForJob(RunnerInterface $runner, string $job): RunnerInterface
{
    try {
        $runner->run()->response($job);

        return $runner;
    } catch (Throwable) {
        // ignore
    }

    return $runner->withRunJob($job);
}

/**
 * Creates a RunInterface instance for the given workflow and named variables .
 */
function run(
    WorkflowInterface $workflow,
    mixed ...$variable,
): RunInterface {
    $run = new Run($workflow, ...$variable);
    $runner = new Runner($run);

    return $runner->withRun()->run();
}
// @codeCoverageIgnoreEnd

function uuidv4(): string
{
    $data = random_bytes(16);

    $data[6] = chr(ord($data[6]) & 0x0F | 0x40);
    $data[8] = chr(ord($data[8]) & 0x3F | 0x80);

    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
