<?php
namespace app\index\controller;
use think\facade\View;
use think\facade\Session;
use think\facade\Cache;
use think\helper\Str;
use think\facade\Db;
use app\common\model\User as UserModel;
use app\common\model\UserTimer as UserTimerModel;
use app\common\model\UserLoginLog as UserLoginLogModel;
use app\common\model\UserWx as UserWxModel;
use app\common\model\UserQq as UserQqModel;
use helper\URL;
class ThirdPartyLogin extends Base
{
    public function thirdParty($type='')
    {
        Session::delete('UserWxId');
        Session::delete('UserQqId');
        switch ($type) {
            case 'qq':
                return $this->qqLogin();
                break;
            case 'wx':
                return $this->wxLogin();
                break;
            default:
                return redirect('/login');
                break;
        }
    }
    const QQ_GET_AUTH_CODE_URL = "https://graph.qq.com/oauth2.0/authorize";
    const QQ_GET_ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token";
    const QQ_GET_OPENID_URL = "https://graph.qq.com/oauth2.0/me";
    const QQ_GET_USERINFO_URL = "https://graph.qq.com/user/get_user_info";
    public function qqLogin()
    {
        $qqLoginConfig=config('qqlogin');
        if (empty($qqLoginConfig['status']) || !$qqLoginConfig['status'])
            return redirect('/system/maintenance?msg=未开通QQ登录');
        $uid=Session::get('User.id');
        if ($uid && UserQqModel::where(['uid'=>$uid])->count())
            return redirect('/user/security');

        //-------生成唯一随机串防CSRF攻击
        $state = md5(uniqid(rand(), TRUE));
        Session::set('qqlogin_state',$state);

        //-------构造请求参数列表
        $keysArr = [
            "response_type" => "code",
            "client_id"     => $qqLoginConfig['appid'],
            "redirect_uri"  => urlencode($qqLoginConfig['redirect_uri']),
            "state"         => $state
        ];

        return redirect(URL::combineURL(self::QQ_GET_AUTH_CODE_URL, $keysArr));
    }

    public function qqCallback(){
        $qqLoginConfig=config('qqlogin');
        if (empty($qqLoginConfig['status']) || !$qqLoginConfig['status'])
            return redirect('/system/maintenance?msg=未开通QQ登录');
        $G=request()->get();
        $state = Session::get('qqlogin_state');
        //--------验证state防止CSRF攻击
        if(!$state || $G['state'] != $state)
            return redirect('/system/maintenance?msg=QQ登录信息验证失败');


        //-------请求参数列表
        $keysArr = array(
            "grant_type"    => "authorization_code",
            "client_id"     => $qqLoginConfig['appid'],
            "redirect_uri"  => urlencode($qqLoginConfig['redirect_uri']),
            "client_secret" => $qqLoginConfig['appkey'],
            "code"          => $G['code'],
            "fmt"           => 'json',
        );

        //------构造请求access_token的url
        $token_url = URL::combineURL(self::QQ_GET_ACCESS_TOKEN_URL, $keysArr);
        $response = URL::get_contents($token_url);
        if (empty($response))
            return redirect('/system/maintenance?msg=获取QQ登录信息失败');
        $accessTokenData = json_decode($response,true);
        if (empty($accessTokenData['access_token']))
        	if (empty($accessTokenData['error_description'])) {
	            return redirect('/system/maintenance?msg=未获取到access_token');
        	}else{
	            return redirect('/system/maintenance?msg='.$accessTokenData['error'].':'.$accessTokenData['error_description']);
        	}
        //-------请求参数列表
        $keysArr = array(
            "access_token"      => $accessTokenData["access_token"],
            "unionid"			=> 1,
            "fmt"           	=> 'json',
        );
        $userinfo_url = URL::combineURL(self::QQ_GET_OPENID_URL, $keysArr);
        $response = URL::get_contents($userinfo_url);
        if (empty($response))
            return redirect('/system/maintenance?msg=获取OpenId失败');
        $openidData = json_decode($response,true);
        if (empty($openidData['openid']))
        	if (empty($openidData['error_description'])) {
	            return redirect('/system/maintenance?msg=未获取到OpenId');
        	}else{
	            return redirect('/system/maintenance?msg='.$openidData['error'].':'.$openidData['error_description']);
        	}

        $UserQqModel=UserQqModel::where(['unionid'=>$openidData['unionid']])->find();
        if (!$UserQqModel)
            $UserQqModel=UserQqModel::where(['pc_openid'=>$openidData['openid']])->find();
        //-------请求参数列表
        $keysArr = array(
            "access_token"      => $accessTokenData["access_token"],
            "oauth_consumer_key"=> $qqLoginConfig['appid'],
            "openid"           	=> $openidData['openid'],
        );
        $userinfo_url = URL::combineURL(self::QQ_GET_USERINFO_URL, $keysArr);
        $response = URL::get_contents($userinfo_url);
        if (empty($response))
            return redirect('/system/maintenance?msg=获取用户信息失败');
        $userInfo = json_decode($response,true);
        Session::set('updateUser',true);
        if (!$UserQqModel || ($UserQqModel && !$UserQqModel->uid)){
            $uid=Session::get('User.id');
            if ($uid && UserQqModel::where(['uid'=>$uid])->count())
                return redirect('/system/maintenance?msg=该用户已绑定QQ');
            if (!$UserQqModel)
	            $UserQqModel=new UserQqModel;
            $UserQqModel->uid           =   $uid?$uid:null;
            $UserQqModel->nickname      =   base64_encode($userInfo['nickname']);
            $UserQqModel->pc_openid     =   $openidData['openid'];
            $UserQqModel->unionid       =   $openidData['unionid'];
            $UserQqModel->gender        =   $userInfo['gender'];
            $UserQqModel->headimgurl    =   $userInfo['figureurl_qq_1'];
            $UserQqModel->city          =   $userInfo['city'];
            $UserQqModel->province      =   $userInfo['province'];
            if ($UserQqModel->save()) {
                if ($uid) {
                    return redirect('/user/security');
                }else{
                    Session::set('UserQqId',$UserQqModel->id);
                    Session::set('BindUserInfo',[
                        'nickname'=>base64_encode($userInfo['nickname']),
                        'headimg'=>$userInfo['figureurl_qq_1'],
                    ]);
                    return redirect('/bind?type=QQ&nickname='.base64_encode($userInfo['nickname']).'&headimgurl='.$userInfo['figureurl_qq_1']);
                }
            }else{
                return redirect('/system/maintenance?msg=更新微信用户信息失败，请重试');
            }
        }else{
            $uid=Session::get('User.id');
            if ($uid && $UserQqModel->uid!==$uid)
                return redirect('/system/maintenance?msg=您已绑定QQ');
            $UserQqModel->nickname      =   base64_encode($userInfo['nickname']);
            $UserQqModel->pc_openid     =   $openidData['openid'];
            $UserQqModel->gender        =   $userInfo['gender'];
            $UserQqModel->headimgurl    =   $userInfo['figureurl_qq_1'];
            $UserQqModel->city          =   $userInfo['city'];
            $UserQqModel->province      =   $userInfo['province'];
            $UserQqModel->save();
            $UserInfo=UserModel::getWebUserInfo(['user.id'=>$UserQqModel->uid]);
            if (!$UserInfo)
                return redirect('/system/maintenance?msg=用户信息不存在');
            if (!$UserInfo['status'])
                return redirect('/system/maintenance?msg='.$UserInfo['disable_msg']);
            $UserTimer = UserTimerModel::where(['uid'=>$UserInfo['id']])->find();
            $UserTimer->login_time=time();
            $UserTimer->login_ip=request()->ip();
            $UserTimer->login_devices=substr(request()->header('user-agent'),0,200);
            $UserLoginLog=new UserLoginLogModel;
            $UserLoginLog->uid=$UserInfo->id;
            $UserLoginLog->appid=request()->ApiInfo['app_id'];
            $UserLoginLog->ip=request()->ip();
            $UserLoginLog->devices_id=substr(request()->header('user-agent'),0,200);
            Db::startTrans();
            try {
                $UserTimer->save();
                $UserLoginLog->save();
                Db::commit();
                $this->setSuccessLogin($UserInfo);
                return redirect('/user');
            } catch (Exception $e) {
                Db::rollback();
                return redirect('/system/maintenance?msg=登录失败，请重试');
            }
        }
        
    }

    public function get_openid(){

        //-------请求参数列表
        $keysArr = array(
            "access_token" => $this->recorder->read("access_token")
        );

        $graph_url = $this->urlUtils->combineURL(self::GET_OPENID_URL, $keysArr);
        $response = $this->urlUtils->get_contents($graph_url);

        //--------检测错误是否发生
        if(strpos($response, "callback") !== false){

            $lpos = strpos($response, "(");
            $rpos = strrpos($response, ")");
            $response = substr($response, $lpos + 1, $rpos - $lpos -1);
        }

        $user = json_decode($response);
        if(isset($user->error)){
            $this->error->showError($user->error, $user->error_description);
        }

        //------记录openid
        $this->recorder->write("openid", $user->openid);
        return $user->openid;

    }
    const WX_GET_AUTH_CODE_URL = "https://open.weixin.qq.com/connect/qrconnect";
    const WX_GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";
    const WX_GET_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo";
    public function wxLogin()
    {
        $wxLoginConfig=config('wxlogin');
        if (empty($wxLoginConfig['status']) || !$wxLoginConfig['status'])
            return redirect('/system/maintenance?msg=未开通微信登录');
        $uid=Session::get('User.id');
        if ($uid && UserWxModel::where(['uid'=>$uid])->count())
            return redirect('/user/security');
        //-------生成唯一随机串防CSRF攻击
        $state = md5(uniqid(rand(), TRUE));
        Session::set('wxlogin_state',$state);

        //-------构造请求参数列表
        $keysArr = [
            "response_type"     => "code",
            "scope"             => "snsapi_login",
            "appid"             => $wxLoginConfig['appid'],
            "redirect_uri"      => $wxLoginConfig['redirect_uri'],
            "state"             => $state
        ];

        return redirect(URL::combineURL(self::WX_GET_AUTH_CODE_URL, $keysArr).'#wechat_redirect');
    }
    public function wxCallback()
    {
        $wxLoginConfig=config('wxlogin');
        if (empty($wxLoginConfig['status']) || !$wxLoginConfig['status'])
            return redirect('/system/maintenance?msg=未开通微信登录');
        $G=request()->get();
        $state = Session::get('wxlogin_state');
        //--------验证state防止CSRF攻击
        if(!$state || $G['state'] != $state)
            return redirect('/system/maintenance?msg=微信登录信息验证失败');

        //-------构造请求参数列表
        $keysArr = [
            "grant_type"        => "authorization_code",
            "appid"             => $wxLoginConfig['appid'],
            "secret"            => $wxLoginConfig['appsecret'],
            "code"              => $G['code']
        ];
        $response=URL::get(static::WX_GET_ACCESS_TOKEN_URL,$keysArr);
        if (empty($response))
            return redirect('/system/maintenance?msg=微信登录信息验证失败');
        $retJson=json_decode($response,true);
        $keysArr = [
            "openid"            => $retJson['openid'],
            "access_token"      => $retJson['access_token']
        ];
        $response=URL::get(static::WX_GET_USERINFO_URL,$keysArr);
        if (empty($response))
            return redirect('/system/maintenance?msg=获取微信用户信息失败');
        $userInfo=json_decode($response,true);
        $UserWxModel=UserWxModel::where(['unionid'=>$userInfo['unionid']])->find();
        if (!$UserWxModel)
            $UserWxModel=UserWxModel::where(['pc_openid'=>$userInfo['openid']])->find();
        Session::set('updateUser',true);
        if (!$UserWxModel || ($UserWxModel && !$UserWxModel->uid)){
            $uid=Session::get('User.id');
            if ($uid && UserWxModel::where(['uid'=>$uid])->count())
                return redirect('/system/maintenance?msg=该用户已绑定微信');
            if (!$UserWxModel)
	            $UserWxModel=new UserWxModel;
            $UserWxModel->uid           =   $uid?$uid:null;
            $UserWxModel->nickname      =   base64_encode($userInfo['nickname']);
            $UserWxModel->pc_openid     =   $userInfo['openid'];
            $UserWxModel->unionid       =   $userInfo['unionid'];
            $UserWxModel->sex           =   $userInfo['sex'];
            $UserWxModel->headimgurl    =   $userInfo['headimgurl'];
            $UserWxModel->city          =   $userInfo['city'];
            $UserWxModel->province      =   $userInfo['province'];
            $UserWxModel->country       =   $userInfo['country'];
            if ($UserWxModel->save()) {
                if ($uid) {
                    return redirect('/user/security');
                }else{
                    Session::set('UserWxId',$UserWxModel->id);
                    Session::set('BindUserInfo',[
                        'nickname'=>base64_encode($userInfo['nickname']),
                        'headimg'=>$userInfo['headimgurl'],
                    ]);
                    return redirect('/bind?type=微信&nickname='.base64_encode($userInfo['nickname']).'&headimgurl='.$userInfo['headimgurl']);
                }
            }else{
                return redirect('/system/maintenance?msg=更新微信用户信息失败，请重试');
            }
        }else{
            $uid=Session::get('User.id');
            if ($uid && $UserWxModel->uid!==$uid)
                return redirect('/system/maintenance?msg=您已绑定微信');
            $UserWxModel->nickname      =   base64_encode($userInfo['nickname']);
            $UserWxModel->pc_openid     =   $userInfo['openid'];
            $UserWxModel->sex           =   $userInfo['sex'];
            $UserWxModel->headimgurl    =   $userInfo['headimgurl'];
            $UserWxModel->city          =   $userInfo['city'];
            $UserWxModel->province      =   $userInfo['province'];
            $UserWxModel->country       =   $userInfo['country'];
            $UserWxModel->save();
            $UserInfo=UserModel::getWebUserInfo(['user.id'=>$UserWxModel->uid]);
            if (!$UserInfo)
                return redirect('/system/maintenance?msg=用户信息不存在');
            if (!$UserInfo['status'])
                return redirect('/system/maintenance?msg='.$UserInfo['disable_msg']);
            $UserTimer = UserTimerModel::where(['uid'=>$UserInfo['id']])->find();
            $UserTimer->login_time=time();
            $UserTimer->login_ip=request()->ip();
            $UserTimer->login_devices=substr(request()->header('user-agent'),0,200);
            $UserLoginLog=new UserLoginLogModel;
            $UserLoginLog->uid=$UserInfo->id;
            $UserLoginLog->appid=request()->ApiInfo['app_id'];
            $UserLoginLog->ip=request()->ip();
            $UserLoginLog->devices_id=substr(request()->header('user-agent'),0,200);
            Db::startTrans();
            try {
                $UserTimer->save();
                $UserLoginLog->save();
                Db::commit();
                $this->setSuccessLogin($UserInfo);
                return redirect('/user');
            } catch (Exception $e) {
                Db::rollback();
                return redirect('/system/maintenance?msg=登录失败，请重试');
            }
        }
    }
    public function setSuccessLogin($UserInfo)
    {
        if (!Session::has('User')) {
            $key=md5('Message:&'.request()->ip().'&'.$UserInfo->id.'&'.time().'&'.Str::random(8));
            $UserInfo->token=$key;
            $UserInfo->client_id=[];
            Session::set('User',$UserInfo->toArray());
            Cache::set('Message::'.$key,$UserInfo->id);
        }
    }
}
