<?php

namespace JinDouYun\Dao;

use Mall\Framework\Core\SqlHelper;
use Mall\Framework\Factory;

use JinDouYun\Cache\AllTableNameCache;

class BaseDao extends SqlHelper
{
    /**
     * @var \Mall\Framework\SearchClient\Client
     */
    private $search;

    /**
     * 当前操作的数据库配置标识
     * @var $serviceDB
     */
    private $serviceDB;

    /**
     * 参考文章: https://www.php.cn/php-weizijiaocheng-403412.html
     * 开启事务数量统计
     * BaseDao constructor.
     * @param string $serviceDB
     */
    private $transactions;

    public function __construct($serviceDB = 'default')
    {
        $this->serviceDB = $serviceDB;

        parent::__construct($serviceDB);

        //$this->setSearchIndex($serviceDB);
    }


    /**
     * 设置搜索引擎配置项
     *
     * @param string $serviceDB
     *
     * @throws \Exception
     * @return \Mall\Framework\SearchClient\Client
     */
    public function setSearchIndex($serviceDB)
    {
        $this->search = Factory::search($serviceDB);

        return $this->search;
    }

    /**
     * 计算分表表名
     *
     * @param string $prefix 表名前缀
     * @param int $id 索引表id
     * @param int $pNumber 分割数量
     *
     * @return string
     */
    public function getTableName($prefix, $id, $pNumber = 500000)
    {
        $prefix = trim($prefix, '_') . '_';

        $tableName = strtolower($prefix . ceil($id / $pNumber));
        return $tableName;
    }

    /**
     * 判断表是否存在
     * @param $tableName
     * @return bool
     */
    public function existsTable($tableName)
    {
        $databaseName = Factory::config()->get('db')[$this->serviceDB]['dbname'];
        if(AllTableNameCache::TableIsExists($databaseName, $tableName)) {
            return true;
        }else{
            return false;
        }
    }

    /**
     * 切换Dao层操作的表
     * 主要用作切换分表使用
     *
     * @param $tableName
     *
     * @throws \Exception
     */
    public function setTable($tableName)
    {
        $this->_table = $tableName;
        $databaseName = Factory::config()->get('db')[$this->serviceDB]['dbname'];

        // 当前使用库所有表名缓存如果不存在自动更新
        if (!AllTableNameCache::allTableNameCacheIsExists($databaseName)) {
            $tables = $this->db->select("SELECT TABLE_NAME FROM INFORMATION_SCHEMA. TABLES WHERE TABLE_SCHEMA = '{$databaseName}';") ?: [];
            if (!empty($tables)) {
                AllTableNameCache::allTableNameCache($databaseName, $tables);
            }
        }

        // 判断切换的表是否存在,不存在自动创建
        if (!AllTableNameCache::TableIsExists($databaseName, $tableName)) {
            $result = explode('_', $tableName);
            if ($result && !empty($result)) {
                $tablePrefix = '';
                for ($i = 0, $c = count($result); $i < ($c - 1); $i++) {
                    if(!is_numeric($result[$i])){
                        $tablePrefix .= $result[$i] . '_';
                    }
                }

                $dbresult = $this->db->query("CREATE TABLE IF NOT EXISTS {$tableName} LIKE {$tablePrefix}1");
                if ($dbresult === false) {
                    throw new \Exception($tableName . '分表创建错误. ErrorInfo: ' . var_export($this->db->error(), true));
                }
            } else {
                throw new \Exception($tableName . '不是一个正确得表名');
            }
            AllTableNameCache::addNewTableName($databaseName, $tableName);
        }
    }

    /**
     * 添加数据
     *
     * @param array $params
     *
     * @return bool|int
     */
    public function insert($params = array(), $multiple = false)
    {
        return parent::insert($params, $multiple);
    }

    /**
     * replace方式添加数据
     *
     * @param array $params
     *
     * @return bool|int
     */
    public function replace($params = array(), $multiple = false)
    {
        return parent::replace($params, $multiple);
    }

    /**
     * 更新数据
     *
     * @param array $data
     * @param null $where
     * @param null $limit
     * @param null $order
     *
     * @return int
     */
    public function update($data = array(), $where = null, $limit = null, $order = null)
    {
        return parent::update($data, $where, $limit, $order);
    }

    /**
     * 删除数据
     *
     * @param null $where
     * @param null $limit
     * @param null $order
     * @param array $data
     *
     * @return int
     */
    public function delete($where = null, $limit = null, $order = null, $data = array())
    {
        return parent::delete($where, $limit, $order, $data);
    }

    /**
     * 数据库自增自减操作
     * @param $fieldName 字段名称
     * @param $id 修改数据id
     * @param $action 操作 "+"/"-"
     * @param $step 修改数据步长
     * @return mixed  影响行数
     *
     */
    public function autodecrement($fieldName, $id, $action, $step)
    {
        $tableName = parent::get_Table();
        $sql = 'call autodecrement("'.$tableName.'", "'.$fieldName.'", '.$id.', "'.$action.'", '.$step.', @result);';
        $dbResult = parent::query($sql);
        if ($dbResult === false) {
            return false;
        }

        $sql = 'select @result as result;';
        $dbResult =  parent::query($sql);
        if ($dbResult === false) {
            return false;
        }
        return $dbResult[0]['result'];
    }


    /**
     * 执行sql
     */
    public function query($sql)
    {
        return parent::query($sql);
    }

    /**
     * 执行sql
     */
    public function exportQuery($sql)
    {
        return parent::exportQuery($sql);
    }

    /**
     * 获取Sql操作错误
     *
     * @return string
     */
    public function error()
    {
        return parent::error();
    }

    /**
     * 过虑字段
     *
     * @param array $params 要筛选的数据
     *
     * @return array
     */
    public function getTablesFields($params)
    {
        $fields = [];

        foreach ($this->_fields as $field) {
            if (array_key_exists($field, $params)) {
                $fields[$field] = $params[$field];
            }
        }

        return $fields;
    }

    /**
     * 开启事务
     * @param bool $foreign_key_checks
     * @return mixed
     */
    public function beginTransaction($foreign_key_checks = false)
    {
        ++$this->transactions;
        if ($this->transactions == 1){
            return parent::beginTransaction($foreign_key_checks = false);
        }
    }

    /**
     * 提交事务
     * @return mixed
     */
    public function commit()
    {
        if($this->transactions == 1){
            return parent::commit();
        }
        --$this->transactions;
    }

    /**
     * 回滚事务
     * @return mixed
     */
    public function rollBack()
    {
        if($this->transactions == 1){
            $this->transactions = 0;
            return parent::rollBack();
        }else{
            --$this->transactions;
        }
    }

    /**
     * 根据DSL查询文档
     *
     * @param $query
     *
     * @return array
     */
    public function getSearchQueryDsl($query)
    {
        return $this->search->search($query);
    }

    /**
     * 根据DSL查询文档  滚动查询
     * @param $query
     * @param string $scroll
     * @param int $size
     * @return mixed
     */
    public function getScrollSearchQueryDsl($query, $scroll = '10s', $size = 2000)
    {
        $result = [];
        $scrollResult = $this->search->scrollSearch($query, $scroll, $size);
        while (isset($scrollResult['hits']['hits']) && count($scrollResult['hits']['hits']) > 0) {
            $result = array_merge($result, $scrollResult['hits']['hits']);

            $scroll_id = $scrollResult['_scroll_id'];

            $scrollResult = $this->search->request('/_search/scroll','POST',[
                    "scroll_id" => $scroll_id,
                    "scroll"    => $scroll
                ],
                false,
                false
            );
        }
        if(!empty($result)) {
            $scrollResult['hits']['hits'] = $result;
        }
        return $scrollResult;
    }

    /**
     * 根据索引的主ID查询文档
     *
     * @param int $id 索引的DocumentId
     *
     * @return array
     */
    public function getSearchIndexDocument($id)
    {
        //$id = intval($id);
        return $this->search->get($id);
    }

    /**
     * 添加或更新ES索引
     *
     * @param array $data 创建索引数据
     * @param int $id 创建索引的DocumentId
     *
     * @return array
     */
    public function addUpSearchIndexDocument($data, $id)
    {
        return $this->search->index($data, $id);
    }

    /**
     * 局部更新索引内容
     * @param array $data 要更新的数据
     * @param int $id 要更新的文档下的数据id
     * @return array
     */
    public function esupdateTypeFieldVaule($data, $id)
    {
        return $this->search->updateFieldVaule($data, $id);
    }

    /**
     * 批量更新索引内容
     * @param $query
     * @param $data
     * @return array
     */
    public function esBatchUpdateTypeFieldVaule($data, $query)
    {
        return $this->search->batchUpdateFieldVaule($data, $query);
    }

    /**
     * 删除索引下面的指定文档
     */
    public function esdeleteTypeDocument($id)
    {
        return $this->search->delete($id);
    }
}