<?php

namespace Application\Service\Extension\Swoole;

use Application\Service\Extension\Laminas;
use Swoole\Coroutine;
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Database\RedisConfig;
use Swoole\Database\RedisPool;

/**
 * swoole 协程连接池
 */
class ConnectPool
{
    /**
     * 连接池大小
     * @var int
     */
    public static int $poolSize = 1000;

    /**
     * redis连接池
     * @var RedisPool|null
     */
    private static ?RedisPool $redis = null;

    /**
     * mysql 连接池
     * @var PDOPool|null
     */
    private static ?PDOPool $db = null;

    /**
     * @var array
     */
    private static array $redisContext = [];

    /**
     * @var array
     */
    private static array $dbContext = [];

    /**
     * 初始化redis连接池
     * @return void
     */
    private static function _getRedis(): void
    {
        if (self::$redis === null) {
            $redisResource = Laminas::$serviceManager->redisExtend->getOptions()->getResourceManager();
            $server = $redisResource->getServer('default');
            self::$redis = new RedisPool((new RedisConfig())
                ->withHost($server['host'])
                ->withPort($server['port'])
                ->withAuth($redisResource->getPassword('default'))
                ->withDbIndex($redisResource->getDatabase('default'))
                ->withTimeout($server['timeout']), self::$poolSize);
        }
    }

    private static function _getDb()
    {
        if (self::$db === null) {
            $dbConfig = Laminas::$app->getConfig()['db']['adapters']['dbAdapter'];
            preg_match('/dbname=(.*)?;host=(.*)?;port=(.*)?;charset=(.*)/', $dbConfig['dsn'], $match);
            self::$db = new PDOPool((new PDOConfig())
                ->withOptions([
                    \PDO::ATTR_ERRMODE => \PDO::ERRMODE_WARNING
                ])
                ->withHost((string)$match[2])
                ->withPort((string)$match[3])
                // ->withUnixSocket('/tmp/mysql.sock')
                ->withDbName((string)$match[1]) //
                ->withCharset((string)$match[4])
                ->withUsername($dbConfig['username'])
                ->withPassword($dbConfig['password']), self::$poolSize);
        }
        return self::$db;
    }


    public static function redis()
    {
        self::_getRedis();

        $cid = Coroutine::getCid();

        if (!isset(self::$redisContext[$cid])) {
            self::$redisContext[$cid] = self::$redis->get();
            \Co\defer(function () use ($cid) {
                self::$redis->put(self::$redisContext[$cid]);
            });
        }

        return self::$redisContext[$cid];
    }

    /**
     * @return mixed|\PDO|\Swoole\Database\PDOProxy
     */
    public static function db()
    {
        self::_getDb();

        $cid = Coroutine::getCid();

        if (!isset(self::$dbContext[$cid])) {
            self::$dbContext[$cid] = self::$db->get();
            \Co\defer(function () use ($cid) {
                self::$db->put(self::$dbContext[$cid]);
            });
        }

        return self::$dbContext[$cid];
    }
}