<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/6/13
 * Time: 9:53
 */
namespace Modules\Base\Services;

use Illuminate\Support\Facades\Log;
use Modules\Base\Entities\Openid;
use Modules\Base\Entities\User;
use Modules\Base\Services\Exception\DisplayEexception;
use Modules\Base\Services\OpenLogin\Weixin;
use SMG\Support\Traits\HasHttpRequest;

class NewOpenloginService extends BaseService
{
    use HasHttpRequest;

    public function __construct(Openid $openid, UserService $userService)
    {
        //$this->model = $openid;
        //$this->userService = $userService;
    }

    public static function getTypes()
    {
        return ['wx_mini', 'test', 'weixin', 'wx_app'];
    }

    /**
     * @param $type
     * @param $data
     * @param null $assocUser
     *
     * @throws \Throwable
     *
     * @return null
     */
    public function login($type, $data, $assocUser = null)
    {
        //获取在OPENID表中的信息，没有会新建一个
        $openUser = $this->getOpenLogin($type, $data);

        $binded = $assocUser && $openUser->user_id && $assocUser->id != $openUser->user_id;

        if ($binded) {
            $msg = '试图绑定的微信账号已经于另一个账号进行了绑定';
            if (request()->is('*api*')) {
                throw new \Exception($msg);
            } else {
                throw new DisplayEexception($msg.'，你可以继续浏览，但支付时将会出现问题');
            }
        }

        //如果没有传关联账号
        if (!$assocUser) {
            if ($openUser->user_id) {
                $assocUser = User::find($openUser->user_id);

                //原绑定用户已删除
                if (!$assocUser) {
                    $assocUser = $this->createUser($openUser);
                    $openUser->user_id = $assocUser->id;
                    $openUser->save();
                }
            } else {
                $assocUser = $this->createUser($openUser);
            }
        }

        /*
         * 更新用户信息
         */
        if (!is_array($assocUser->ext) || !isset($assocUser->ext[$type.'_openid'])) {
            $assocUser->saveExt([$type => $openUser->extra, $type.'_openid' => $openUser->openid]);
        }

        if (!$openUser->user_id) {
            $openUser->user_id = $assocUser->id;
            $openUser->save();
        }

        return $assocUser;
    }

    protected function createUser($openUser)
    {
        $type = $openUser->type;

        $data = ['password' => 'temp', 'ext' => [$type => $openUser->extra, $type.'_openid' => $openUser->openid]] + $openUser->getUserExt();
        $data['password'] = \Hash::make($data['password']);

        return User::create($data);
    }

    /**
     * @param $type
     * @param $data
     *
     * @throws \Throwable
     *
     * @return mixed
     */
    public function getOpenLogin($type, $data)
    {
        throw_unless(
            in_array($type, self::getTypes()),
            \Illuminate\Validation\ValidationException::withMessages([
                'type' => ['错误的登陆类型'],
            ])
        );

        $info = $this->parseInfo($type, $data);

        throw_if(!$info['openid'], '\Exception', '未获取到OPENID');

        $openLogin = Openid::firstOrNew(['openid' => $info['openid']], $info);

        if (!$openLogin->user_id && $openLogin->unionid) {
            $same = Openid::where(['unionid' => $openLogin->unionid])->first();

            if ($same) {
                $openLogin->user_id = $same->user_id;
                $openLogin->save();
            }
        }

        return $openLogin;
    }

    protected function parseInfo($type, $data)
    {
        if ($type == 'wx_mini') {
            $use_unionid = true;

            $result = $this->getWxMini($data, $use_unionid);

            if (!$use_unionid) {
                return [
                    'type' => $type,
                    'openid' => $result['openid'],
                    'unionid' => $result['unionid'] ?? null,
                    'extra' => $result,
                ];
            }

            return [
                'type' => $type,
                'openid' => $result['openId'],
                'unionid' => $result['unionId'] ?? null,
                'extra' => $result,
            ];
        } elseif ($type == 'weixin') {
            //$info = Weixin::getAccessToken();
            //$result = Weixin::getUserInfo($info['access_token'], $info['openid']);

            //Log::channel('openlogin')->info('office_account');
            //Log::channel('openlogin')->info($result);

            $result = $data;

            return [
                'type' => $type,
                'openid' => $result['openid'],
                'unionid' => $result['unionid'] ?? null,
                'extra' => $result,
            ];
        } elseif ($type == 'wx_app') {
            $info = Weixin::getAccessToken();
            $result = Weixin::getUserInfo($info['access_token'], $info['openid']);

            Log::channel('openlogin')->info('app_account');
            Log::channel('openlogin')->info($result);

            //$result = $data;

            return [
                'type' => $type,
                'openid' => $result['openid'],
                'unionid' => $result['unionid'] ?? null,
                'extra' => $result,
            ];
        } elseif ($type == 'test') {
            return [
                'type' => $type,
                'openid' => $data['code'],
            ];
        }

        return [];
    }

    protected function getWxMini($data, $use_unionid = false)
    {
        if (!isset($data['code']) || !$data['code']) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'code' => ['code必须'],
            ]);
        }

        $app = app('wechat.mini_program');
        $result = $app->auth->session($data['code']);

        Log::channel('openlogin')->info('wx_mini');
        Log::channel('openlogin')->info($result);

        if (isset($result['errcode'])) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'code' => [$result['errmsg']],
            ]);
        }

        if (!$use_unionid) {
            return $result;
        }

        if (!isset($data['encryptedData']) || !$data['encryptedData']) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'encryptedData' => ['encryptedData必须'],
            ]);
        }

        if (!isset($data['iv']) || !$data['iv']) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'iv' => ['iv必须'],
            ]);
        }

        $decryptedData = $app->encryptor->decryptData($result['session_key'], $data['iv'], $data['encryptedData']);

        Log::channel('openlogin')->info($decryptedData);

        return $decryptedData;
    }

    /**
     * 小程序解密数据
     *
     * @param $iv
     * @param $encryptData
     * @param int $user_id
     *
     * @return bool|array
     */
    public function decryptData($iv, $encryptData, $user_id = 0)
    {
        $user_id || $user_id = auth()->id();

        if (!$user_id) {
            return false;
        }

        $openid = $this->model->where('user_id', $user_id)->where('type', 'weixin')->first();
        $session_key = array_get($openid, 'session_key');
        if (!$session_key) {
            return false;
        }
        $app = app('wechat.mini_program');
        $decryptedData = $app->encryptor->decryptData($session_key, $iv, $encryptData);
        if ($decryptedData && isset($decryptedData)) {
            return $decryptedData;
        }

        return false;
    }
}
