<?php

namespace Application\Service\Extension\Store;

use Application\Service\Extension\BaseExtension;
use Application\Service\Extension\Context;
use Application\Service\Extension\Helper\DataHelper;
use Application\Service\Extension\Params\Params;
use Swoole\Coroutine;

/**
 * @method dbFind(string $dbClass, int $primaryKey)
 * @method formStruct(int $formId)
 */
class Store extends BaseExtension
{
    protected static array $_container = [];

//    private bool $__isToParams = false;

    private array $_callMapping = [
        /** @see StoreFunctionMapping::dbFind */
        'dbFind' => [Mapping::class, 'dbFind'],
        'formStruct' => [Mapping::class, 'formStruct'],
    ];

    public static function app(): Store
    {
        if (!self::isInstance()) {
            self::setInstance(new Store());
        }
        // 返回全局实例
        return self::getInstance();
    }

    public function set($key, $value)
    {
        Context::set(DataHelper::md5($key), new StoreValue($value));
//        self::$_container[Coroutine::getCid()][DataHelper::md5($key)] = new StoreValue($value);
    }

    /**
     * @param $key
     * @param null $default
     * @return Params|mixed|null
     * @throws \Exception
     */
    public function get($key, $default = null)
    {
        $key = DataHelper::md5($key);
        $val = Context::get($key);
        return $val instanceof StoreValue ? $val->value() : $default;
        $val = isset(self::$_container[Coroutine::getCid()][DataHelper::md5($key)]) ? self::$_container[Coroutine::getCid()][DataHelper::md5($key)]->value() : $default;

//        if ($this->__isToParams === true && is_array($val)) {
//            return new Params($val);
//        }

        return $val;
    }

    public function getOrSet($key, $callable = null, ?array $arguments = [])
    {
        if (!($val = Context::get(DataHelper::md5($key))) instanceof StoreValue) {
            if (is_array($callable)) {
                $val = call_user_func_array($callable, [...$arguments]);
            } else {
                $val = $callable();
            }
            $this->set($key, $val);
            return $val;
        }

        return $val->value();
    }

//    public function toParams(): Store
//    {
//        $this->__isToParams = true;
//        return $this;
//    }

    public function __call($name, $arguments)
    {
        $key = $name . DataHelper::md5($arguments);
        if (isset($this->_callMapping[$name])) {
            return $this->getOrSet($key, $this->_callMapping[$name], $arguments);
        }

        throw new \Exception("Not support Method: `$name` ");
    }
}