package com.flossom.miniProgram.service.impl;

import com.alibaba.fastjson.JSON;
import com.flossom.common.core.constant.CacheConstants;
import com.flossom.common.core.constant.UserConstants;
import com.flossom.common.core.domain.R;
import com.flossom.common.core.domain.RegisterBody;
import com.flossom.common.core.domain.entity.WxUserMember;
import com.flossom.common.core.exception.ServiceException;
import com.flossom.common.core.mapper.WxUserMemberMapper;
import com.flossom.common.core.utils.DateUtils;
import com.flossom.common.core.utils.StringUtils;
import com.flossom.common.redis.service.RedisService;
import com.flossom.common.security.utils.SecurityUtils;
import com.flossom.miniProgram.domain.vo.*;
import com.flossom.miniProgram.service.IWxUserMemberService;
import com.flossom.miniProgram.utils.MiniProgramUtils;
import com.flossom.system.api.RemoteAuthService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class WxUserMemberServiceImpl implements IWxUserMemberService {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private WxUserMemberMapper wxUserMemberMapper;

    @Autowired
    private RemoteAuthService remoteAuthService;

    @Autowired
    private RedisService redisService;

    @Override
    public LoginUserVo login(String code) throws Exception {
        // 1、使用临时凭证 code 获取 appi + appsecret + unionid
        String result = MiniProgramUtils.getSessionKeyAndOpenId(code);
        logger.info("请求微信服务器获取openid和unionid，返回结果：{}", result);
        WxCode2SessionRet wxCode2SessionRet = JSON.parseObject(result, WxCode2SessionRet.class);
        if (wxCode2SessionRet.getErrcode() != null) {
            logger.error(wxCode2SessionRet.getErrmsg());
            throw new ServiceException("校验失败");
        }
        logger.info("openid = {}", wxCode2SessionRet.getOpenid());
        logger.info("unionid = {}", wxCode2SessionRet.getUnionid());

        // 2、根据 openid 查询用户信息
        WxUserMember wxUserMember = wxUserMemberMapper.selectWxUserMemberByOpenId(wxCode2SessionRet.getOpenid());
        if (wxUserMember == null) {
            // 未注册用户，就注册游客账户
            // 2.1、封装微信用户信息
            wxUserMember = new WxUserMember();
            wxUserMember.setOpenid(wxCode2SessionRet.getOpenid());
            wxUserMember.setUnionid(wxCode2SessionRet.getUnionid());
            wxUserMember.setLoginTime(DateUtils.getNowDate());
            wxUserMember.setCreateTime(DateUtils.getNowDate());
            // 2.2、微信用户表注册
            wxUserMemberMapper.insertWxUserMember(wxUserMember);
            // 2.3、系统表注册
            RegisterBody registerBody = new RegisterBody();
            registerBody.setUsername(wxUserMember.getOpenid());
            registerBody.setPassword(UserConstants.WX_SYSTEM_USER_PASSWORD);
            R<?> registerResult = remoteAuthService.register(registerBody);
            if (R.FAIL == registerResult.getCode()) {
                logger.error("测试后台账号失败：{}", registerResult.getMsg());
                throw new ServiceException(registerResult.getMsg());
            }
        }

        // 3、登录请求，获取 token
        R<Map<String, String>> loginResult = remoteAuthService.wxLogin(wxUserMember);
        if (loginResult.getCode() == R.FAIL) {
            logger.error("获取token失败：{}", loginResult.getMsg());
            throw new ServiceException(loginResult.getMsg());
        }
        /**
         * TODO: 将 session_key 缓存在 redis，并且由于官方没有规定 session_key 的有效期，所以使用时候要注意如下：
         *        当需要使用的时候，需要前端先判断微信的登录态是否过期（wx.checkSession()）
         *          1、如果过期，重新调用登录接口获取新的 session_key
         *          2、如果没过期，但由于security的拦截器会判断过期时间不足120分钟时会，会对session_key进行续期：{@link com.flossom.common.security.service.TokenService#refreshSessionKey}
         */
        redisService.setCacheObject(CacheConstants.WX_SESSION_KEY_CACHE + wxUserMember.getOpenid(),
                wxCode2SessionRet.getSession_key(), CacheConstants.EXPIRATION, TimeUnit.MINUTES);

        // 4、返回登录信息
        LoginUserVo loginUserVo = new LoginUserVo();
        BeanUtils.copyProperties(wxUserMember, loginUserVo);
        loginUserVo.setToken(loginResult.getData().get("access_token"));
        logger.info("登录用户信息：id = {}, username = {}, token={}", loginUserVo.getId(), loginUserVo.getUsername(), loginUserVo.getToken());
        return loginUserVo;
    }

    @Override
    public String upgradeMember(String code) throws Exception {
        // 获取手机号
        String result = MiniProgramUtils.getPhone(code);
        logger.info("请求微信服务器获取手机号码返回结果：{}", result);
        WxCode2PhoneRet wxCode2PhoneRet = JSON.parseObject(result, WxCode2PhoneRet.class);
        if (wxCode2PhoneRet.getErrcode() != 0) {
            logger.error("获取用户手机号码失败: {}", wxCode2PhoneRet.getErrmsg());
            throw new ServiceException("获取用户手机号码失败");
        }
        wxUserMemberMapper.upgradeMember(wxCode2PhoneRet.getPhoneInfo().getPhoneNumber(), SecurityUtils.getLoginUser().getWxUserMember().getId().intValue());
        return wxCode2PhoneRet.getPhoneInfo().getPhoneNumber();
    }

    @Override
    public void updateUser(UserMemberUpdateVo userMemberUpdateVo) {
        // 完善用户信息, 判断是否标记完善信息
        WxUserMember wxUserMember = SecurityUtils.getLoginUser().getWxUserMember();
        if (wxUserMember.getIsCompleteInformation() == null ||
                wxUserMember.getIsCompleteInformation() == 0) {
            // 修改完善
            wxUserMember.setIsCompleteInformation(1);
            // TODO： 首次完善，增加加分

        }
        BeanUtils.copyProperties(userMemberUpdateVo, wxUserMember);
        wxUserMember.setUpdateTime(DateUtils.getNowDate());
        wxUserMemberMapper.updateWxUserMember(wxUserMember);
    }


}
