<?php
/**
 *  ╔═══════════════════════════════════════════════════╗
 *  ║                                                   ║
 *  ║     ██╗  ██╗   █████╗    ██████╗                  ║
 *  ║     ██║  ██║  ██╔══██╗  ██╔═══██╗                 ║
 *  ║     ███████║  ███████║  ██║   ██║                 ║
 *  ║     ██╔══██║  ██╔══██║  ██║   ██║                 ║
 *  ║     ██║  ██║  ██║  ██║  ╚██████╔╝   SNS           ║
 *  ║                                                   ║    
 *  ║                                                   ║    
 *  ║     © 2023 HaoSNS™ All Rights Reserved            ║
 *  ║     官方网站: https://www.haosns.com                *
 *  ║     本代码由赣州乐易网络科技有限公司®提供             *
 *  ║                                                    *
 *  ║   未经授权禁止复制、传播或用于其他商业目的            *
 *  ║                                                   ║
 *  ╚═══════════════════════════════════════════════════╝
 */



namespace app\api\service;
use app\common\{logic\UserLogic,
    model\User,
    model\UserAuth,
    enum\UserTerminalEnum,
    service\ConfigService,
    service\storage\Driver as StorageDriver};
use think\Exception;

/**
 * 用户功能类（主要微信登录后创建和更新用户）
 * Class UserService
 * @package  app\api\service
 */
class WechatSerService
{
    protected int       $terminal   = UserTerminalEnum::WECHAT_MMP;
    protected array     $response   = [];
    protected ?string   $code       = null;
    protected ?string   $openid     = null;
    protected ?string   $unionid    = null;
    protected ?string   $nickname   = null;
    protected ?string   $headimgurl = null;
    protected User      $user;


    public function __construct(array $response,int $terminal)
    {
        $this->terminal = $terminal;
        $this->setParams($response);
    }

    /**
     * @notes 设置微信返回的用户信息
     * @param $response
     */
    private function setParams($response):void
    {
        $this->response     = $response;
        $this->openid       = $response['openid'];
        $this->unionid      = $response['unionid'] ?? '';
        $this->nickname     = $response['nickname'] ?? '';
        $this->headimgurl   = $response['headimgurl'] ?? '';
    }


    /**
     * @notes 根据微信opendid或unionid获取用户信息
     */
    public function getResopnseByUserInfo($source = ''):self
    {

        $user = User::hasWhere('userAuth',['openid'=>$this->openid],'id,sn,nickname,avatar,mobile,disable')
            ->findOrEmpty();
        /*
         * 用户没有该端记录，且微信返回了unionid，则用unionid找该用户
         * 如果是小程序的静默登录，只按open_id找用户信息，如果没有用户信息，返回空，前端重新调用授权登录接口。
         */
        if($user->isEmpty() && $this->unionid && 'silent' != $source ){
            $user = User::hasWhere('userAuth',['unionid'=>$this->unionid],'id,sn,nickname,avatar,mobile,disable')
                ->findOrEmpty();
        }

        $this->user = $user;
        return $this;
    }


    /**
     * @notes
     * @param bool $isCheck 是否验证账号是否可用
     * @return array
     * @throws Exception
     */
    public function getUserInfo($isCheck = true):array
    {
        if(!$this->user->isEmpty() && $isCheck){
            $this->checkAccount();
        }
        if(!$this->user->isEmpty()){
            $this->getToken();
        }
        return $this->user->toArray();
    }


    /**
     * @notes 验证账号是否可用
     * @return bool|string
     */
    private function checkAccount()
    {
        if($this->user->disable){
            throw new Exception('您的账号异常，请联系客服。');
        }

    }



    /**
     * @notes 创建用户
     * @throws Exception
     */
    private function createUser():void
    {

        // 获取存储引擎
        $config = [
            'default' => ConfigService::get('storage', 'default', 'local'),
            'engine'  => ConfigService::get('storage')
        ];
        //设置头像
        if (empty($this->headimgurl)) {
            //默认头像
            $avatar = ConfigService::get('config', 'default_avatar', '');

        } else {
            if ($config['default'] == 'local') {
                $file_name = md5($this->openid . time()) . '.jpeg';
                $avatar = download_file($this->headimgurl, 'uploads/user/avatar/', $file_name);
            } else {
                $avatar = 'uploads/user/avatar/' . md5($this->openid . time()) . '.jpeg';
                $StorageDriver = new StorageDriver($config);
                if (!$StorageDriver->fetch($this->headimgurl, $avatar)) {
                    throw new Exception( '头像保存失败:'. $StorageDriver->getError());
                }
            }

        }
        //todo 后续补充用户资料
        $this->user->nickname           = $this->nickname;
        $this->user->sn                 = create_user_sn();
        $this->user->avatar             = $avatar;
        $this->user->code               = generate_code();
        $this->user->register_source    = $this->terminal;

        if (empty($this->nickname)) {
            $this->user->nickname = '用户'. $this->user->sn;
        }

        $this->user->save();
        (new UserAuth)->save([
            'user_id'       => $this->user->id,
            'openid'        => $this->openid,
            'unionid'       => $this->unionid,
            'terminal'      => $this->terminal,
        ]);

        //todo 注册后其他业务逻辑
        UserLogic::registerAward($this->user->id);

        //消息通知
        //Hook::listen('notice', ['user_id' => $user_id, 'scene' => NoticeSetting::REGISTER_SUCCESS_NOTICE]);

    }

    /**
     * 更新用户信息（如果该端没授权信息，会重新写入一条该端的授权信息）
     * @param $response
     * @param $client
     * @param $user_id
     * @return array|\PDOStatement|string|\think\Model|null
     */
    private function updateUser():void
    {

        $this->user->nickname = $this->nickname;

        //无头像需要更新头像
        if (empty($this->user->avatar)) {
            // 获取存储引擎
            $config = [
                'default' => ConfigService::get('storage', 'default', 'local'),
                'engine'  => ConfigService::get('storage_engine')
            ];

            if ($config['default'] == 'local') {
                $file_name = md5($this->openid . time()) . '.jpeg';
                $avatar = download_file($this->headimgurl, 'uploads/user/avatar/', $file_name);

            } else {

                $avatar = 'uploads/user/avatar/' . md5($this->openid . time()) . '.jpeg';
                $StorageDriver = new StorageDriver($config);
                if (!$StorageDriver->fetch($this->headimgurl, $avatar)) {
                    throw new Exception( '头像保存失败:'. $StorageDriver->getError());
                }
            }

            $this->user->avatar = $avatar;
        }
        $this->user->save();

        $userAuth = UserAuth::where(['user_id'=>$this->user->id,'openid'=>$this->openid])->findOrEmpty();
        //无该端信息，新增一条
        if($userAuth->isEmpty()){

            $userAuth->user_id = $this->user->id;
            $userAuth->openid  = $this->openid;
            $userAuth->unionid = $this->unionid;
            $userAuth->terminal= $this->terminal;
            $userAuth->save();
        }



    }

    /**
     * @notes 获取token
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function getToken()
    {
        $user = UserTokenService::setToken($this->user->id,$this->terminal);
        $this->user->token = $user['token'];
    }


    /**
     * @notes 用户授权登录，
     * 如果用户不存在，创建用户；用户存在，更新用户信息，并检查该端信息是否需要写入
     * @return WechatSerService
     * @throws Exception
     */
    public function authUserLogin():self
    {
        if($this->user->isEmpty()){
            $this->createUser();
        }else{
            $this->updateUser();
        }
        return $this;
    }
}