<?php

/**
 * DBContainer.php
 * 文件描述
 * Created On 2021/12/16
 * @author yuanb yuanbo0x@gmail.com
 */

namespace Framework\DB;

use Library\Common\Singletons;
use Framework\Define\DBDefine;
use Framework\Define\ErrorDefine;
use Framework\Log\LogMark;
use Library\DB\IRedis;
use Library\DB\RedisColony;
use Library\DB\RedisSingle;

class DBContainer
{
    use Singletons;

    private DBDefine $redis_config;

    private array $redis_handle;

    public function init(DBDefine $config)
    {
        $this->redis_config = $config;
        $this->redis_handle = array();
    }

    public function getRedisByTable(string $table): ?IRedis
    {
        $id = $this->redis_config->getTypeByTable($table);
        if ($id == 0) {
            LogMark::getInstance()->markCritical(
                ErrorDefine::DB_TABLE_TYPE_ERROR,
                "db table covert to db type fail",
                array("table" => $table)
            );
            return null;
        }
        return $this->getRedisByConfig($id);
    }

    public function getRedisByConfig(int $id): ?IRedis
    {
        if (array_key_exists($id, $this->redis_handle)) {
            return $this->redis_handle[$id];
        }
        $info = $this->redis_config->getRedisLinkInfo($id);
        if ($info == null) {
            LogMark::getInstance()->markCritical(
                ErrorDefine::REDIS_LINK_INFO_ERROR,
                "redis link info null",
                array("config" => $id)
            );
            return null;
        }
        $redis_db = null;
        switch ($info->db_mode) {
            case DBDefine::MODEL_SINGLE:
                $redis_db = $this->createSingleRedis($info->ip, $info->port);
                break;
            case DBDefine::MODEL_CLUSTER:
                $redis_db = $this->createClusterRedis($info->node);
                break;
        }
        if ($redis_db == null) {
            return null;
        }
        $this->redis_handle[$id] = $redis_db;
        return $redis_db;
    }

    /**
     * @param $ip
     * @param $port
     * @return IRedis|null
     */
    private function createSingleRedis($ip, $port): ?IRedis
    {
        $redis = new RedisSingle();
        if ($redis->createRedis(array($ip, $port))) {
            return $redis;
        }
        LogMark::getInstance()->markCritical(
            ErrorDefine::REDIS_CREATE_SINGLE_FAIL,
            "create single redis fail",
            array("ip" => $ip, "port" => $port)
        );
        return null;
    }

    /**
     * @param array $node
     * @return IRedis|null
     */
    private function createClusterRedis(array $node): ?IRedis
    {
        $redis = new RedisColony();
        if ($redis->createRedis($node)) {
            return $redis;
        }
        LogMark::getInstance()->markCritical(
            ErrorDefine::REDIS_CREATE_CLUSTER_FAIL,
            "create redis cluster fail",
            $node
        );
        return null;
    }
}
