<?php

use App\Models\SystemLog;
use App\Services\ExceptionService;
use App\Services\FileService;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

/**
 * 调用服务方法
 * @param mixed $params 调用参数
 * @return object 服务实例
 */
function serv(...$params){
    static $_servers;
    $serviceName = ucfirst($params[0]);
    if (!isset($_servers)) {
        $_servers = [];
    }
    $serverId = md5(base64_encode(json_encode($params)));
    if (isset($_servers[$serverId])){
        return $_servers[$serverId];
    }
    $identity = strtolower($serviceName);
    try {
        $className = $serviceName . "Service";
        if (!class_exists($className)) {
            $className = "\Server\\{$identity}\\{$serviceName}Service";
        }
        if (!class_exists($className)) {
            $servicePath = MICRO_SERVER . $identity . "/{$serviceName}Service.php";
            if (file_exists($servicePath)) {
                require_once $servicePath;
                $className = class_exists($serviceName . 'Service') ? $serviceName . 'Service' : MICRO_SERVER . $identity . "/{$serviceName}Service.php";
            }
            if (!class_exists($className)){
                return new ExceptionService("Service $serviceName Not Found.");
            }
        }
        if (count($params)>1){
            array_splice($params, 0, 1);
            $instance = new $className(...$params);
        }else{
            $instance = new $className();
        }
        $instance->serviceId = $serverId;
        $instance->identity = $identity;
        if ($instance->service['status']!=1 || !$instance->enabled){
            return new ExceptionService("Service $className has stopped.");
        }
    }catch (Exception $exception){
        SystemLog::systemRunning(
            "微服务启动失败",
            'service:start',
            $exception->getMessage(),
            false,
            [
                'file' => $exception->getFile() . ":" . $exception->getLine(),
                'code' => $exception->getCode(),
                'trace' => $exception->getTrace(),
                'service' => $identity,
                'params' => $params,
            ]
        );
        return new ExceptionService($exception->getMessage());
    }
    $_servers[$serverId] = $instance;
    return $instance;
}

function assets($path, $secure = null){
    if ($secure!==null){
        return asset($path, $secure);
    }
    if (strpos($path, 'http')===0){
        return $path;
    }
    if (file_exists(public_path($path)) && !\Str::startsWith($path, "/")){
        $path = "/" . $path;
    }
    return $path;
}

if (!function_exists('post_var')){
    function post_var($keys=array(),$datas=array()){
        global $_GPC;
        $data = array();
        $datas = $datas ?: $_GPC;
        foreach ($keys as $key){
            if (isset($datas[$key])){
                $data[$key] = $datas[$key];
            }
        }
        return $data;
    }
}

function script_run($params, $basedir = MICRO_SERVER){
    if (empty($params['content'])) return true;
    $basedir = preg_replace('/\/$/',"", $basedir);
    switch ($params['drive']){
        case 'php':{
            //运行PHP文件
            $php = $basedir."/{$params['content']}";
            if (file_exists($php)){
                include $php;
            }
            break;
        }
        case 'phpscript':{
            //有风险
            eval($params['content']);
            break;
        }
        case 'sql':{
            pdo_query($params['content']);
            break;
        }
        case 'shell':{
            $sh = $basedir."/{$params['content']}";
            shell_exec($sh);
            break;
        }
        case 'shellscript':{
            shell_exec($params['content']);
            break;
        }
        default : break;
    }
    return true;

}

function strexists($string, $find) {
    return \Str::contains($string,$find);
}

function array_elements($keys, $src, $default = false) {
    $return = array();
    if (!is_array($keys)) {
        $keys = array($keys);
    }
    foreach ($keys as $key) {
        if (isset($src[$key])) {
            $return[$key] = $src[$key];
        } else {
            $return[$key] = $default;
        }
    }
    return $return;
}

function checksubmit($var='_token'){
    global $_GPC,$_W;
    if (!$_W['ispost']) return false;
    if ($_W['inConsole']){
        $headers = request()->header('X-CSRF-TOKEN');
        return !empty($_GPC[$var]) || ($var=='_token' && !empty($headers));
    }elseif (defined('IN_API') && $var=='_token'){
        return true;
    }
    return isset($_GPC[$var]);
}

function cache_load($key, $unserialize = false, $default=null){
    $cache = Cache::get($key, $default);
    if (empty($cache) || $cache===$default){
        return $cache;
    }
    if ($unserialize){
        return unserialize($cache);
    }
    return $cache;
}

function cache_delete($key){
    return Cache::forget($key);
}

function cache_set($key, $data, $expire = null){
    return cache_write($key, $data, $expire);
}

function cache_write($key, $data, $expire = null) {
    if (empty($expire)){
        return Cache::forever($key, $data);
    }
    return Cache::put($key, $data, $expire);
}

function cache_read($key, $default=null){
    return Cache::get($key, $default);
}

function referer() {
    global $_GPC, $_W;
    $_W['referer'] = !empty($_GPC['referer']) ? $_GPC['referer'] : $_SERVER['HTTP_REFERER'];
    $_W['referer'] = '?' == substr($_W['referer'], -1) ? substr($_W['referer'], 0, -1) : $_W['referer'];

    $_W['referer'] = str_replace('&amp;', '&', $_W['referer']);
    $reUrl = parse_url($_W['referer']);
    $reHost = (empty($reUrl['port']) || $reUrl['port']==80) ? $reUrl['host'] : $reUrl['host'].":".$reUrl['port'];

    if (!empty($reHost) && !in_array($reHost, array($_SERVER['HTTP_HOST'], 'www.' . $reHost)) && !in_array($_SERVER['HTTP_HOST'], array($reHost, 'www.' . $reHost))) {
        $_W['referer'] = $_W['siteroot'];
    } elseif (empty($reUrl['host'])) {
        $_W['referer'] = $_W['siteroot'] . './' . $_W['referer'];
    }

    return strip_tags($_W['referer']);
}

function wurl($segment="", $params = array(), $contain_domain = false){
    global $_W;
    $url = 'console';
    if ($contain_domain){
        $url = $_W['siteroot'] . $url;
    }else{
        $url = '/' . $url;
    }
    if (!empty($segment)){
        $segment = str_replace('.','/',$segment);
        $url .= \Str::startsWith($segment, '/') ? $segment : '/' . $segment;
    }
    if (!empty($params)) {
        $queryString = http_build_query($params, '', '&');
        $url .= '?' . $queryString;
    }
    return $url;
}

function murl($segment, $params = array(), $noredirect = true, $addhost = false) {
    global $_W;
    if (strexists($segment,'.')){
        $segment = str_replace('.','/',$segment);
    }
    if (!empty($addhost)) {
        $url = $_W['siteroot'] . "app";
    } else {
        $url = "/app";
    }

    if (!empty($segment)){
        $url .= \Str::startsWith($segment, '/') ? $segment : '/' .$segment;
    }

    if (empty($params)){
        $params = array();
    }
    $params['i'] = $_W['uniacid'];

    $queryString = http_build_query($params, '', '&');
    $url .= '?' . $queryString;
    if (false === $noredirect) {
        $url .= '&wxref=mp.weixin.qq.com#wechat_redirect';
    }

    return $url;
}

function tomedia($src, $local_path = false, $is_cahce = false) {
    global $_W;
    $src = trim($src);
    if (empty($src)) {
        return '';
    }
    if ($is_cahce) {
        $src .= '?v=' . time();
    }

    $t = strtolower($src);
    if (strexists($t, '//mmbiz.qlogo.cn') || strexists($t, '//mmbiz.qpic.cn')) {
        $url = '?a=image&attach='.$src;

        return wurl('util/wxcode') . ltrim($url, '.');
    }

    if (\Str::startsWith($src,'//')) {
        return preg_replace('/^\/\//', $_W['sitescheme'], $src);
    }
    if (\Str::startsWith($src,'http://') || \Str::startsWith($src,'https://')) {
        return $src;
    }
    if (\Str::startsWith($src,'/') && file_exists(public_path($src))){
        return defined('IN_SYS') ? assets($src) : $_W['siteroot'] . preg_replace('/^\//', '', $src);
    }
    if (file_exists($src)){
        $baseDir = dirname($src);
        if (strexists($baseDir, 'storage' . DIRECTORY_SEPARATOR . 'app/public' . DIRECTORY_SEPARATOR)){
            return $_W['siteroot'] . 'storage/' . preg_replace('/^.+storage\/app\/public\//', "", $src);;
        }elseif (strexists($baseDir, 'public' . DIRECTORY_SEPARATOR)){
            return $_W['siteroot'] . preg_replace('/^.+public\//', "", $src);
        }
        return '';
    }

    if ($local_path || empty($_W['setting']['remote']['type']) || file_exists(storage_path("app/public/$src") )) {
        $src = $_W['siteroot'] . 'storage/' . $src;
    } else {
        return $_W['attachurl'] . $src;
    }

    return $src;
}

function globalMedia($src){
    if (empty($src)) {
        return '';
    }
    global $_W;
    if (\Str::startsWith($src,'http://') || \Str::startsWith($src,'https://')) {
        return $src;
    }
    if (\Str::startsWith($src,'//')) {
        return preg_replace('/^\/\//', $_W['sitescheme'], $src);
    }
    if (file_exists(public_path($src))){
        return assets($src);
    }
    if (empty($_W['attachurl_global'])){
        $attach_global = $_W['attachurl_local'];
        $_W['attachurl_global_remote'] = "";
        $remoteSet = serv('storage', 0)->settings['remote'];
        if (!empty($remoteSet['type'])){
            $attach_global = FileService::getRemoteUrl($remoteSet);
            $_W['attachurl_global_remote'] = $attach_global;
        }
        $_W['attachurl_global'] = $attach_global;
    }
    if (empty($_W['attachurl_global_remote']) || file_exists(storage_path("app/public/$src"))){
        return $_W['attachurl_local'] . $src;
    }
    return $_W['attachurl_global'] . $src;
}

function res_path($path = ''): string
{
    return app()->make('path.public.resource').($path ? DIRECTORY_SEPARATOR.ltrim($path, DIRECTORY_SEPARATOR) : $path);
}

function random($len,$is_number=false){
    if($is_number){
        $len = min(9, intval($len));
        $len = max(1, $len);
        $start = (int)pow(10,$len-1);
        $stop = (int)pow(10,$len) - 1;
        return random_int($start, $stop);
    }
    return \Str::random($len);
}

function is_error($data) {
    if (empty($data) || !is_array($data) || !array_key_exists('errno', $data) || (array_key_exists('errno', $data) && 0 == $data['errno'])) {
        return false;
    } else {
        return true;
    }
}

function error($errno, $message = '') {
    return array(
        'errno' => $errno,
        'message' => $message
    );
}

function debugInfo(){
    global $_W;
    if ($_W['config']['debugMode']){
        $_W['debugInfo'] = array(
            'runtime'=>number_format((microtime(true) - $_W['startTime']), 6)
        );
        return $_W['debugInfo'];
    }
    return false;
}

function session_exit($print=''){
    if (!empty($print)){
        echo $print;
    }
    session()->save();
    exit();
}

function tablename($table) {
    $prefix = env("DB_PREFIX", 'ims_');
    return "`$prefix$table`";
}

function pdo_get($tablename, $condition = array(), $fields = array()) {
    $query = DB::table($tablename)->where($condition);
    if (empty($fields)){
        return $query->first();
    }
    return $query->first($fields);
}

function pdo_getall($tablename, $condition = array(), $fields = array(), $keyfield = '', $orderBy = array(), $limit = array()) {
    $query = DB::table($tablename)->where($condition);
    if ($fields){
        $query = $query->select($fields);
    }
    if (!empty($orderBy)){
        if(is_array($orderBy) && count($orderBy) == 2 && in_array($orderBy[1], ['asc','desc'])){
            $query = $query->orderBy($orderBy[0],$orderBy[1]);
        }else{
            $orderByRaw = is_array($orderBy) ? implode(',',$orderBy) : $orderBy;
            $query = $query->orderByRaw($orderByRaw);
        }
    }
    if ($limit){
        $query = $query->offset($limit[0])->limit($limit[1]);
    }
    if ($keyfield){
        $res = $query->get()->keyBy($keyfield)->toArray();
    }else{
        $res = $query->get()->toArray();
    }
    return $res;
}

function pdo_fetchall($sql, $params = array(), $keyfield = '') {
    $result = DB::select($sql,$params);
    if (!empty($result) && $keyfield){
        $keys = array_column($result, $keyfield);
        return empty($keys) ? $result : array_combine($keys, $result);
    }
    return $result;
}

function pdo_fetchcolumn($sql, $params = array(), $column = 0) {
    $result = DB::selectOne($sql,$params);
    if (!empty($result)){
        $keys = array_keys($result);
        if (isset($result[$keys[$column]])){
            return $result[$keys[$column]];
        }
    }
    return null;
}

function pdo_fetch($sql, $params = array()) {
    return DB::selectOne($sql,$params);
}

function pdo_getcount($tablename, $condition=array()){
    return DB::table($tablename)->where($condition)->count();
}

function pdo_getcolumn($tablename, $condition, $field) {
    return DB::table($tablename)->where($condition)->value($field);
}

function pdo_truncate($tablename){
    DB::table($tablename)->truncate();
    return true;
}

function pdo_insert($tablename,$data,$insertgetid=false){
    $GLOBALS['_W']['__db_last_inserid_'] = DB::table($tablename)->insertGetId($data);
    return $GLOBALS['_W']['__db_last_inserid_'];
}

function pdo_insertid(){
    return $GLOBALS['_W']['__db_last_inserid_'];
}

function pdo_insertgetid($tablename,$data){
    return DB::table($tablename)->insertGetId($data);
}

function pdo_update($table, $data = array(), $params = array()) {
    return DB::table($table)->where($params)->update($data);
}

function pdo_delete($table, $params = array()) {
    return DB::table($table)->where($params)->delete();
}

function pdo_count($tablename, $condition = array(), $cachetime = 15) {
    return DB::table($tablename)->where($condition)->count();
}

function pdo_indexexists($tablename, $indexname = ''){
    if (!Schema::hasTable($tablename)){
        return false;
    }
    if (!empty($indexname)){
        $indexs = DB::select("SHOW INDEX FROM ".tablename($tablename));
        if (!empty($indexs) && is_array($indexs)) {
            foreach ($indexs as $row) {
                if ($row['Key_name'] == $indexname) {
                    return true;
                }
            }
        }
    }
    return false;
}

function pdo_fieldexists($tablename, $fieldname = '') {
    return Schema::hasColumn($tablename,$fieldname);
}

function pdo_tableexists($tablename) {
    return Schema::hasTable($tablename);
}

function pdo_run($sql) {
    return DB::statement($sql);
}

function pdo_query($sql, $params = array()) {
    $prefix = env("DB_PREFIX", 'ims_');
    $sql = str_replace(array("ims_", "ENGINE=MyISAM"), array($prefix, "ENGINE=InnoDB"), $sql);
    return DB::statement($sql, $params);
}
