<?php

declare(strict_types=1);

namespace App\Middleware\Auth;

use App\Constants\HttpEnumCode;
use App\Model\User;
use App\Utils\Auth;
use App\Utils\Jwt;
use App\Utils\Log;
use Hyperf\Context\Context;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
use Hyperf\Redis\Redis;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class AuthMiddleware implements MiddlewareInterface
{
    /**
     * @var ContainerInterface
     */
    protected ContainerInterface $container;

    protected HttpResponse $response;

    protected RequestInterface $request;

    public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
    {
        $this->container = $container;
        $this->response = $response;
        $this->request = $request;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $redis = $this->container->get(Redis::class);
        $path_info = $this->request->getPathInfo();
        $method = $this->request->getMethod();

        $Auth = new Auth();
        $Jwt = new Jwt();

        // 打印入参请求-临时
        $request_params = $this->request->all();
        Log::getInstance()->info("请求地址 ".$path_info);
        Log::getInstance()->info("请求方式 ".$method);
        Log::getInstance()->info("请求参数 ".json_encode($request_params,JSON_UNESCAPED_UNICODE));


        // 获取token
        $token = $this->getHeaderToken();

        // 检测接口是否为免鉴权接口
        $white_api = $Auth->checkApiWhiteList($path_info, $method);

        if (!empty($token)){
            if ($white_api){
                // 存在token，免鉴权
                $res = $redis->get('jwt_black_' . $token);
                if ($res && time() >= $res) {
                    // token存在黑名单中
                    return $handler->handle($request);
                }

                // jwt验证
                try {
                    $result = $Jwt->decode($token);
                }catch (\Throwable $e) {
                    return $handler->handle($request);
                }
            }else{
                // 存在token，鉴权
                $res = $redis->get('jwt_black_' . $token);
                if ($res && time() >= $res) {
                    // token存在黑名单中
                    return $this->response->json(fail(HttpEnumCode::HTTP_PROHIBIT));
                }

                // jwt验证
                $result = $Jwt->decode($token);

                // 处理即将过期token
                $req = $Auth->checkTokenExpTime($result);
                if ($req) {
                    // 即将过期，重新下发token
                    $new_token = $Jwt->encode($result['userInfo']);

                    // 旧token加入黑名单 5天有效期，5天内，无法继续进行访问
                    $res = $redis->set('jwt_black_' . $token, $result['exp'], 30);
                    if (!$res) {
                        // 添加缓存失败
                        return $this->response->json(fail(HttpEnumCode::SERVER_ERROR));
                    }

                    $response = Context::get(ResponseInterface::class);
                    $response = $response->withHeader('Authorization', $new_token);
                    Context::set(ResponseInterface::class, $response);
                }
            }
        }else{
            if ($white_api){
                // token为空，免鉴权
                return $handler->handle($request);
            }else{
                // token为空，鉴权
                return $this->response->json(fail(HttpEnumCode::TOKEN_ERROR));
            }
        }

        if (empty($result)){
            return $this->response->json(fail(HttpEnumCode::SERVER_ERROR));
        }

        // 检测用户状态
        $params = array();
        $params['user_id'] = $result['userInfo']['user_id'];
        $user = User::getOne($params);

        if (empty($user)){
            return $this->response->json(fail(HttpEnumCode::HTTP_ERROR));
        }

        if ($user['user_status'] == 0){
            return $this->response->json(fail(HttpEnumCode::USER_STATUS_DISABLE));
        }

        if ($user['user_status'] != 1){
            return $this->response->json(fail(HttpEnumCode::USER_STATUS_ERROR));
        }

        $request = $this->request->withAttribute('userInfo', $result['userInfo']);

        $request = Context::set(ServerRequestInterface::class, $request);

        return $handler->handle($request);
    }

    /**
     * 获取header中的token
     * @return string
     */
    protected function getHeaderToken(): string
    {
        $bearer_token = $this->request->getHeader('Authorization');
        if (empty($bearer_token)){
            return "";
        }

        // 解析token
        $token = explode(' ', $bearer_token[0]);

        return $token[1] ?? "";
    }


}
