<?php

namespace app\common\arw\adjfut\src;

use app\common\arw\adjfut\src\Traits\Event;

class ReTry
{
    use Event;
    /**
     * 执行器
     *
     * @var callable
     */
    private $handle = null;
    /**
     * 是否执行成功
     *
     * @var boolean
     */
    private $success = false;
    /**
     * 执行上限
     *
     * @var integer
     */
    private $limit = 3;
    /**
     * 上次执行原始上限
     *
     * @var integer
     */
    private $last_limit = 3;
    /**
     * 执行次数
     *
     * @var integer
     */
    private $count = 1;
    /**
     * 包装器
     *
     * @param callable $handle
     * @param integer $limit
     * @return self
     * @date 2022-12-30
     * @example
     * @author arw
     * @since 1.0.0
     */
    public static function wrapper(callable $handle, int $limit = 3): self
    {
        $ins = new self;
        $ins->setHandle($handle);
        $ins->setLimit($limit);
        return $ins;
    }
    /**
     * 自增
     *
     * @param integer $step 步长
     * @return self
     * @date 2022-12-28
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function inc(int $step = 1): self
    {
        $this->limit += $step;
        return $this;
    }
    /**
     * 自减
     *
     * @param integer $step
     * @return self
     * @date 2022-12-28
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function dec(int $step = 1): self
    {
        $this->limit -= $step;
        return $this;
    }

    /**
     * 获取执行次数
     *
     * @return integer
     * @date 2022-12-30
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function getCount(): int
    {
        return $this->count;
    }

    /**
     * 获取执行上限
     *
     * @return integer
     * @date 2022-12-28
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function getLimit(): int
    {
        return $this->limit;
    }

    /**
     * 设置执行上限
     *
     * @param integer $limit
     * @return self
     * @date 2022-12-28
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function setLimit(int $limit): self
    {
        $this->limit = $limit;
        $this->last_limit = $limit;
        return $this;
    }

    /**
     * 设置执行器
     *
     * @param callable $cb
     * @return self
     * @date 2022-12-28
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function setHandle(callable $cb): self
    {
        $this->handle = $cb;
        return $this;
    }

    /**
     * 执行是否成功
     *
     * @param boolean $success
     * @return self
     * @date 2022-12-28
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function success(bool $success): self
    {
        $this->success = $success;
        return $this;
    }

    /**
     * 重试上限
     *
     * @param callable $cb
     * @return self
     * @date 2022-12-28
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function onRetryMax(callable $cb): self
    {
        $this->event('reTryMax', $cb);
        return $this;
    }

    /**
     * 执行异常
     *
     * @param callable $cb
     * @return self
     * @date 2022-12-30
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function onError(callable $cb): self
    {
        $this->event('error', $cb);
        return $this;
    }

    /**
     * 执行
     *
     * @param mixed ...$args
     * @return void
     * @date 2022-12-30
     * @example
     * @author arw
     * @since 1.0.0
     */
    public function run(...$args)
    {
        $this->reset();
        array_unshift($args, $this);
        $handle = $this->handle;
        $res = null;
        while (true) {
            try {
                $res = call_user_func_array($handle, $args);
            } catch (\Throwable $th) {
                $this->trigger('error', [$th]);
            }
            $this->count++;
            // 执行成功
            if ($this->success) {
                break;
            }
            // 执行上限
            if ($this->count > $this->limit) {
                // 不减1会导致 获取到的执行次数多1
                $this->count--;
                $this->trigger('reTryMax');
                break;
            }
        }
        return $res;
    }

    /**
     * 重置执行器
     *
     * @return void
     * @date 2022-12-30
     * @example
     * @author arw
     * @since 1.0.0
     */
    private function reset(): void
    {
        $this->count = 1;
        $this->setLimit($this->last_limit);
    }
}
