<?php

namespace App\Tool;


use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;
/**
 * Class Log
 * @package Myaf\Log
 */
class Log
{
    /**
     * 日志唯一id.
     */
    const LOG_REQUEST_ID = 'requestUniqueId';

    /**
     * 是否为测试模式.
     * @var bool
     */
    private static $debug = false;

    /**
     * 本次http请求的唯一id.
     * @var string
     */
    private static $requestId = '';

    /**
     * 当前应用名称。
     * @var string
     */
    private static $app = '';
    private static $outPutLevel = [];
    /**
     * 日志存储目录.
     * @var string
     */
    private static $logPath = '';
    /**
     * 全局唯一标识
     * @var string
     */
    private static $uuid = '';
    private static $userid = '';
    /**
     * 二维数组日志存储器.
     * @var array
     */
    private static $logs = [];
    private static $request = '';
    private static $ext = [];
    /**
     * 开启将每次记录都写日志
     * @var bool
     */
    private static $autoFlush = true;

    /**
     * 初始化日志系统.
     *
     * @param $app string 当前应用名字
     * @param $logPath string 日志存储路径
     * @param $timeZone string 默认时区
     * @param $debug bool 是否为测试环境
     */
    public  function __construct(Request $request,Auth $auth,$logPath = '/data/logs', $timeZone = 'Asia/Shanghai', $debug = false)
    {


        //$conf = json_decode(File::get('/tmp/env.conf'), true);
        $this->auth = $auth;
        self::$userid = $this->auth::user()->id ?? '';
        self::$uuid = '20181010181818123';
        self::$app = 'offcn-media-resource';
        self::$debug = $debug;

        self::$request = $request;
        self::$logPath = $logPath;
        self::$ext = [
            'header' => self::$request->header(),
            'param'  => self::$request->all(),
        ];
        self::$requestId = self::getGlobalRequestId();
        $this->setOutLevel();
        date_default_timezone_set($timeZone);

    }
    public static function setOutLevel() {
        $temp = ['DEBUG','WARN','FATAL','INFO','ERROR'];
        if ( !empty(self::$outPutLevel) ) {
            self::$outPutLevel =  array_intersect($temp,self::$outPutLevel);
        }
        if (empty(self::$outPutLevel)) {
            self::$outPutLevel = $temp;
        }
    }
    /**
     * 设置自动刷日志
     *
     * @param bool $flag
     */
    public static function setAutoFlush($flag = false)
    {

        self::$autoFlush = $flag;
    }


    /**
     * 获取全局唯一请求id.
     * 如果未设置则从$_GET、$_POST参数中区搜索.
     * 如果还未找到则直接创建.
     *
     * @return string
     */
    public static function getGlobalRequestId()
    {
        if (!self::$requestId) {
            try {
                if (isset($_GET[self::LOG_REQUEST_ID]) && $_GET[self::LOG_REQUEST_ID]) {
                    self::$requestId = $_GET[self::LOG_REQUEST_ID];
                } elseif (isset($_POST[self::LOG_REQUEST_ID]) && $_POST[self::LOG_REQUEST_ID]) {
                    self::$requestId = $_POST[self::LOG_REQUEST_ID];
                } else {
                    self::$requestId = uniqid();
                }
            } catch (Exception $e) {
                self::$requestId = uniqid();
            }
        }
        return self::$requestId;
    }

    /**
     * debug日志
     *
     * @param string $route 路由
     * @param string $uid 用户类信息(例如: 相关用户id或用户名或手机号等)
     * @param string $code 业务错误码
     * @param string $msg 业务错误信息
     * @param string|array|number $ext 标准扩展字段
     * @throws Exception
     */
    public static function debug( $uid = '', $code = '', $msg = '', ...$ext)
    {
        self::append('DEBUG', $uid, $code, $msg, $ext);
    }

    public static  function _invoke($method,$args = []) {
        $reflection = new \ReflectionMethod(__CLASS__, $method);
        $pass = [];
        foreach($reflection->getParameters() as $param) {
            if(isset($args[$param->getName()])) {
                $pass[] = $args[$param->getName()];
            } else {
                if ($param->getName() != 'ext') {
                    $pass[] = $param->getDefaultValue();
                }
            }
        }
        $pass[] = [];
        return $reflection->invokeArgs(null, $pass);
    }
    /**
     * 常规日志
     *
     * @param string $route 路由
     * @param string $uid 用户类信息(例如: 相关用户id或用户名或手机号等)
     * @param string $code 业务错误码
     * @param string $msg 业务错误信息
     * @param string|array|number $ext 标准扩展字段
     * @throws Exception
     */
    public static  function info( $uid = '', $code = '', $msg = '', ...$ext)
    {
        if ( is_array($uid) ) {
            return self::_invoke(__FUNCTION__,$uid);
        }
        self::append('INFO',$uid, $code, $msg, $ext);
    }


    /**
     * 警告日志
     *
     * @param string $route 路由
     * @param string $uid 用户类信息(例如: 相关用户id或用户名或手机号等)
     * @param string $code 业务错误码
     * @param string $msg 业务错误信息
     * @param string|array|number $ext 标准扩展字段
     * @throws Exception
     */
    public static function warn( $uid = '', $code = '', $msg = '', ...$ext)
    {
        if ( is_array($uid) ) {
            return self::_invoke(__FUNCTION__,$uid);
        }
        self::append('WARN', $uid, $code, $msg, $ext);
    }

    /**
     * 挂掉日志
     *
     * @param string $route 路由
     * @param string $uid 用户类信息(例如: 相关用户id或用户名或手机号等)
     * @param string $code 业务错误码
     * @param string $msg 业务错误信息
     * @param string|array|number $ext 标准扩展字段
     * @throws Exception
     */
    public static function fatal($route = '', $uid = '', $code = '', $msg = '', ...$ext)
    {
        if ( is_array($uid) ) {
            return self::_invoke(__FUNCTION__,$uid);
        }
        self::append('FATAL', $route, $uid, $code, $msg, $ext);
    }


    /**
     * 错误日志
     *
     * @param string $route 路由
     * @param string $uid 用户类信息(例如: 相关用户id或用户名或手机号等)
     * @param string $code 业务错误码
     * @param string $msg 业务错误信息
     * @param string|array|number $ext 标准扩展字段
     * @throws Exception
     */
    public static function error( $uid = '', $code = '', $msg = '', ...$ext)
    {
        if ( is_array($uid) ) {
            return self::_invoke(__FUNCTION__,$uid);
        }
        self::append('ERROR', $uid, $code, $msg, $ext);
    }


    /**
     * 将此次访问的的所有日志录入相关日志文件.
     * @return bool
     * @throws Exception
     */
    public static function flush()
    {
        if (empty(self::$logs)) {
            return true;
        }
        if (!$logPath = realpath(self::$logPath)) {
            if (!$logPath = is_dir(self::$logPath)) {
                if (!mkdir($logPath, 0777, true)) {
                    throw new Exception("can not mkdir {$logPath}");
                }
            }
        }
        $logFileName = realpath($logPath) . DIRECTORY_SEPARATOR . self::$app.self::$uuid.'_'.date('Y-m-d').'.json';
        foreach (self::$logs as $item) {
            self::writeFile($logFileName, $item);
        }
        self::$logs = [];
        return true;
    }

    /**
     * 将日志压入内存暂存器.
     *
     * @param $level string 日志等级
     * @param string $route 路由
     * @param string $uid 用户类信息(例如: 相关用户id或用户名或手机号等)
     * @param string $code 业务错误码
     * @param string $msg 业务错误信息
     * @param mixed $ext 标准扩展字段
     * @throws Exception
     */
    private static function append($level,  $uid = '', $code = '', $msg = '', $ext = '')
    {
        if (!self::$requestId || !self::$logPath) {
            throw new Exception('log not initialized');
        }
        if (!empty($ext)) {
            self::$ext = array_merge(self::$ext,$ext[0]);
        }

        if (in_array($level,self::$outPutLevel)) {
            $logContent = [];
            $logContent['date'] = date('Y-m-d H:i:s');
            $logContent['ip'] = self::$request->ip();
            $logContent['level'] = $level;
            $logContent['app'] = self::$app;
            $logContent['uniqid'] = getmypid();
            $logContent['path'] = self::$request->path();
            $logContent['user_id'] = $uid ?? self::$userid;
            $logContent['code'] = $code;
            $logContent['msg'] = $msg;
            $logContent['ext'] = self::$ext;
            $logString = json_encode($logContent, JSON_UNESCAPED_UNICODE);
            array_push(self::$logs, $logString);
            if (self::$autoFlush) {
                self::flush();
            }
        }
    }

    /**
     * 写入日志文件
     *
     * @param string $logFile
     * @param string $content
     * @return true
     */
    private static function writeFile($logFile, $content)
    {
        $fp = fopen($logFile, 'a');
        if (flock($fp, LOCK_EX)) {
            fwrite($fp, $content . "\n");
            flock($fp, LOCK_UN);
        }
        fclose($fp);
        return true;
    }

    /**
     * 获取日志内容字符串
     *
     * @param $logContent
     * @return string
     */
    private static function getLogString($logContent)
    {
        foreach ($logContent as $k => $content) {
            if (!$content) {
                $content = '-';
            }
            if (is_array($content)) {
                $logContent[$k] = json_encode($content, JSON_UNESCAPED_UNICODE);
            }
        }
        $logString = implode('|', $logContent);
        return $logString;
    }
}
