<?php

namespace Lib;

/**
 * @author:dc
 * @time 2023/2/13 15:07
 * Class App
 * @package Lib
 */
class App {

    /**
     * @var App
     */
    public static App $instance;

    /**
     * 当前日期
     * @var string
     */
    private string $date = '';

    /**
     * 当前时间
     * @var string
     */
    private string $dateTime = '';

    /**
     * @var Route
     */
    private Route $route;

    /**
     * 请求的参数
     * @var array
     */
    private array $request = [];


    /**
     * TODO:: 如果debug打开,错误时会返回错误消息到前端
     * @var bool
     */
    public bool $debug = false;

    /**
     * 输出到前端的数据
     * @var mixed
     */
    private mixed $data = [];

    /**
     * 表单文件
     * @var array
     */
    private array $uploadFile = [];

    /**
     * 错误
     * @var array
     */
    private array $error = [];

    /**
     * App constructor.
     */
    public function __construct()
    {

        register_shutdown_function("\\Lib\\App::end");

        $this->date = date('Y-m-d');
        $this->dateTime = date('Y-m-d H:i:s');


        // 路由
        $this->route = new Route();

        // 请求参数 TODO::不允许其他类型的请求参数
        $this->request = my_filter($_REQUEST,['trim']);

        // 调试
        if(defined('APP_DEBUG')){
            $this->debug = boolval(APP_DEBUG);
        }

    }


    /**
     * @return App
     * @author:dc
     * @time 2023/2/13 10:37
     */
    public static function instance(){
        if(empty(static::$instance)){
            static::$instance = new App();
        }
        return static::$instance;
    }


    /**
     * 开始运行
     * @author:dc
     * @time 2023/2/13 11:15
     */
    public static function run() {
        $app = self::instance();
        try {
//            if ($_SERVER['REQUEST_METHOD'] != 'POST'){
//                $app->e('need_post_request');
//            }

            // 取到路由 控制器
            $route = $app->route->get(explode('?',$_SERVER['REQUEST_URI'])[0]);
            if(!$route){
                $app->e('route_not_found');
            }

            list($class,$action) = $route;
            $controller = new $class();

            $app->data = $controller->{$action}();

            // end 控制器


        }catch (\Throwable $exception){

            if($exception instanceof Err){

                if ($exception->getCode() !== 200){
                    $app->data = [
                        'error_message' => $exception->getMessage(),
                        'status'    =>  $exception->getCode() ? $exception->getCode() : 500,
                    ];
                }

            }else{

                $app->error = [
                    'message' => $exception->getMessage(),
                    'file' => $exception->getFile(),
                    'line' => $exception->getLine(),
                    'traceAsString' =>  $exception->getTraceAsString()
                ];

                // 非 Err 错误类型
                $app->data = [
                    'error_message' => $app->debug ? $exception->getMessage().PHP_EOL.$exception->getTraceAsString() : __('server_error'),
                    'status'    =>  $exception->getCode() ? $exception->getCode() : 500,
                ];
            }

        }

    }

    /**
     * 请求的参数
     * @param string $name
     * @param null $default
     * @param array|string|null $filter
     * @return array|false|float|int|mixed|null
     * @author:dc
     * @time 2023/2/17 9:37
     */
    public function request($name='*',$default=null,$filter = null){
        $data = [];
        if($name === '*'){
            $data = $this->request;
        } else if (is_string($name)){
            $data = $this->request[$name]??$default;
        }else if(is_array($name)){
            foreach ($this->request as $key=>$value){
                if(in_array($key,$name)){
                    $data[$key] = $value;
                }
            }
        }
        if($filter){
            $data = my_filter($data,$filter);
        }
        if($data !== []){
            return $data;
        }
        return null;
    }

    /**
     * 读取数组
     * @param string $name
     * @param array $default
     * @param null $filter
     * @return array|float|int|mixed|string[]
     * @author:dc
     * @time 2024/8/6 9:36
     */
    public function requestArr($name='*',array $default = [], $filter = null){
        $value = $this->request($name,$default, $filter);
        if(!is_array($value)){
            $value = explode(',',$value);
        }
        foreach ($value as $k=>$v){
            if($v===''){
                unset($value[$k]);
            }
        }
        if(!$value){
            return $default;
        }
        return $value;
    }

    /**
     * 是否存在
     * @param string $name
     * @return bool
     * @author:dc
     * @time 2023/4/15 16:43
     */
    public function requestHas(string $name):bool {
        return isset($this->request[$name]);
    }


    /**
     * @param string $key
     * @return false|UploadFile[]
     * @author:dc
     * @time 2023/3/13 15:09
     */
    public function file($key='file'){
        if(!empty($this->uploadFile[$key])){
            return $this->uploadFile[$key];
        }
        if(empty($_FILES[$key])){
            return false;
        }

        if (is_array($_FILES[$key]['error'])){
            foreach ($_FILES[$key]['error'] as $k=>$e){
                // 成功的才处理
                if($e===0){
                    $this->uploadFile[$key][] = new UploadFile($_FILES[$key]['name'][$k],$_FILES[$key]['tmp_name'][$k]);
                }
            }
        }else if($_FILES[$key]['error']===0){
            $this->uploadFile[$key][] = new UploadFile($_FILES[$key]['name'],$_FILES[$key]['tmp_name']);
        }

        return $this->uploadFile[$key]??false;

    }




    /**
     * @return string
     * @author:dc
     * @time 2023/2/13 11:17
     */
    public function nowDate():string {
        return $this->date;
    }

    /**
     * @return string
     * @author:dc
     * @time 2023/2/13 11:18
     */
    public function nowDateTime():string{
        return $this->dateTime;
    }

    /**
     * 错误
     * @param string|array $message
     * @param int $status
     * @throws Err
     * @author:dc
     * @time 2023/2/13 10:57
     */
    public function e($message,$status=400){
        if(is_array($message)){
            $this->data['error_message'] = __($message[0]);
            if(is_array($message[1])){
                $this->data['error_message'] = sprintf($this->data['error_message'],...$message[1]);
            }else{
                unset($message[0]);
                $this->data['error_message'] = sprintf($this->data['error_message'],...$message);
            }
        }else{
            $this->data['error_message'] = __($message);
        }
        $this->data['status'] = $status;
        throw new Err($this->data['error_message'],$status);
    }

    /**
     * 成功消息
     * @param $data
     * @param string $message
     * @throws Err
     * @author:dc
     * @time 2023/2/13 11:03
     */
    public function _json($data){
        $this->data = $data;
        throw new Err('',200);
    }


    /**
     * @param $data
     * @param int $http_code
     * @author:dc
     * @time 2023/3/27 10:53
     */
    public static function echo($data, $http_code = 200){


        if(php_sapi_name()=='cli'){
            return $data;
        }

        http_response_code($http_code);

        if(is_array($data)){
            @header("Content-Type:application/json;Charset=UTF-8;");
            echo json_encode($data,JSON_UNESCAPED_UNICODE);
        }else{
            @header("Content-Type:text/html;Charset=UTF-8;");
            echo $data;
        }
    }

    public function getError(){
        return $this->error;
    }

    /**
     * 结束
     * @author:dc
     * @time 2023/2/13 10:54
     */
    public static function end()
    {

        $app = self::instance();

        // 记录日志
        $last_error = error_get_last();
        if($last_error){
            logs($last_error);

            if($last_error == E_ERROR){
                $data['error_message'] = $last_error['message'];
                $data['status'] = 502;

                if($app->debug){
                    $data['debug']  =   $last_error;
                }

                self::echo($data,502);

                return true;
            }

        }


        if($app->getError()){
            logs($app->getError());
        }

        self::echo($app->data);


        // 日志记录
        Log::getInstance()->write();

//        header("Content-Type:text/event-stream;Charset=UTF-8;");

//        ob_flush();
//        ob_clean();
    }




}