package ink.wgink.login.wechat.service.sign.impl;

import com.alibaba.fastjson.JSONObject;
import ink.wgink.exceptions.PropertiesException;
import ink.wgink.exceptions.SearchException;
import ink.wgink.exceptions.WechatAccessTokenForUserException;
import ink.wgink.exceptions.WechatUserInfoException;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.login.base.service.BaseAppSignService;
import ink.wgink.login.wechat.pojo.bos.miniapp.MiniappPhoneDataBO;
import ink.wgink.login.wechat.pojo.vos.sign.MiniappLoginVO;
import ink.wgink.login.wechat.pojo.vos.update.MiniappUpdatePhoneVO;
import ink.wgink.login.wechat.service.sign.IMiniappSignService;
import ink.wgink.module.wechat.manager.MiniappManager;
import ink.wgink.module.wechat.pojo.bos.miniapp.MiniappUserInfoBO;
import ink.wgink.module.wechat.pojo.pos.miniapp.MiniappUserPO;
import ink.wgink.module.wechat.service.miniapp.IMiniappUserCreateHandleService;
import ink.wgink.module.wechat.service.miniapp.IMiniappUserService;
import ink.wgink.properties.wechat.miniapp.MiniappProperties;
import ink.wgink.service.user.pojo.pos.UserPO;
import ink.wgink.service.user.pojo.vos.UpdateUsernameVO;
import ink.wgink.service.user.service.IUserService;
import ink.wgink.util.AesUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: MiniAppSignServiceImpl
 * @Description: 小程序登录
 * @Author: wanggeng
 * @Date: 2021/4/8 5:14 下午
 * @Version: 1.0
 */
@Service
public class MiniappSignServiceImpl extends BaseAppSignService implements IMiniappSignService {

    @Autowired
    private MiniappProperties miniappProperties;
    @Autowired
    private IMiniappUserService miniappUserService;
    @Autowired
    private IUserService userService;
    @Autowired(required = false)
    private IMiniappUserCreateHandleService miniappUserCreateHandleService;

    @Override
    public String defaultSign(MiniappLoginVO miniAppLoginVO) throws Exception {
        if (miniAppLoginVO == null) {
            throw new PropertiesException("未有相关配置");
        }
        Map<String, Object> params = new HashMap<>(2);
        params.put("appid", miniappProperties.getAppKey());
        params.put("secret", miniappProperties.getAppSecret());
        params.put("js_code", miniAppLoginVO.getJsCode());
        params.put("grant_type", miniappProperties.getGrantType());

        StringBuilder url = new StringBuilder(miniappProperties.getAuthorizeUrl());
        url.append("?appid={appid}&secret={secret}&js_code={js_code}&grant_type={grant_type}");
        RestTemplate restTemplate = new RestTemplate();

        String resultJson = restTemplate.getForObject(url.toString(), String.class, params);
        MiniappUserInfoBO miniappUserInfoBO = JSONObject.parseObject(resultJson, MiniappUserInfoBO.class);
        if (miniappUserInfoBO == null) {
            throw new WechatUserInfoException("获取微信用户信息失败");
        }
        if (miniappUserInfoBO.getErrcode() != null && miniappUserInfoBO.getErrcode() != 0) {
            throw new WechatAccessTokenForUserException(String.format("获取用户信息失败，错误码：%s，错误信息：%s", miniappUserInfoBO.getErrcode(), miniappUserInfoBO.getErrmsg()));
        }
        LOG.debug("绑定用户");
        String userId = miniappUserService.createAndReturnUserId(miniappProperties.getAppKey(), miniappUserInfoBO.getOpenid());
        UserPO userPO = userService.getPO(userId);
        if (userPO == null) {
            throw new SearchException("用户不存在");
        }
        // 加入管理队列
        MiniappManager.getInstance().addUser(userId, miniappUserInfoBO);
        if (miniappUserCreateHandleService != null) {
            // 自定义新增处理
            miniappUserCreateHandleService.handle(userPO, miniappUserInfoBO.getOpenid());
        }
        return getMiniappToken(userPO);
    }

    @Override
    public String updatePhone(String token, MiniappUpdatePhoneVO miniappUpdatePhoneVO) throws UnsupportedEncodingException {
        String userId = getAppTokenUser(token).getId();
        MiniappPhoneDataBO miniappPhoneData = getMiniappPhoneData(userId, miniappUpdatePhoneVO);
        UserPO userPO = userService.getPO(userId);
        if (userPO == null) {
            throw new SearchException("非系统用户，请刷新小程序");
        }
        String phone = miniappPhoneData.getPhoneNumber();
        UserPO userPOByUsername = userService.getPOByUsername(phone);
        if (userPOByUsername != null) {
            LOG.debug("手机号存在");
            // 不是当前用户，抛异常
            if (StringUtils.equals(userId, userPOByUsername.getUserId())) {
                throw new SearchException("该手机已经绑定");
            }
            // 是当前用户，重复绑定，返回token
            MiniappManager.getInstance().refreshUserUpdateTime(userId);
            return getToken(userPO);
        }
        // 手机不存在，更新手机号
        MiniappUserPO miniappUserPO = miniappUserService.getPO(userId);
        if (miniappUserPO == null) {
            throw new SearchException("未绑定为系统用户，请刷新小程序");
        }
        LOG.debug("手机不存在，更新用户名");
        UpdateUsernameVO updateUsernameVO = new UpdateUsernameVO();
        updateUsernameVO.setUsername(phone);
        updateUsernameVO.setUpdateReason("微信用户手动更新");
        userService.updateUsername(userId, updateUsernameVO, false);
        LOG.debug("返回token");
        UserPO newUserPO = new UserPO();
        BeanUtils.copyProperties(userPO, newUserPO);
        newUserPO.setUserUsername(phone);
        miniappUserService.updateIsInitAccount(userId, 0);
        // 更新管理队列
        MiniappManager.getInstance().refreshUserUpdateTime(userId);
        return getMiniappToken(userPO);
    }

    /**
     * 解密获得手机号
     *
     * @param userId
     * @param miniappUpdatePhoneVO
     * @return
     */
    private MiniappPhoneDataBO getMiniappPhoneData(String userId, MiniappUpdatePhoneVO miniappUpdatePhoneVO) {
        MiniappUserInfoBO miniappUserInfoBO = MiniappManager.getInstance().get(userId);
        if (miniappUserInfoBO == null) {
            throw new SearchException("会话不存在，请重新打开小程序");
        }
        byte[] encryptedBytes = Base64.decodeBase64(miniappUpdatePhoneVO.getEncryptedData());
        byte[] keyBytes = Base64.decodeBase64(miniappUserInfoBO.getSession_key());
        byte[] ivBytes = Base64.decodeBase64(miniappUpdatePhoneVO.getIv());
        byte[] userInfoBytes = AesUtil.aesCommonDecoderDetail(keyBytes, encryptedBytes, ivBytes, AesUtil.PKCS_7);
        return JSONObject.parseObject(userInfoBytes, MiniappPhoneDataBO.class);
    }

    /**
     * 获得小程序token
     *
     * @param userPO 用户对象
     * @return
     * @throws UnsupportedEncodingException
     */
    private String getMiniappToken(UserPO userPO) throws UnsupportedEncodingException {
        String isRandomUsername = ISystemConstant.IS_FALSE_INT;
        if (userPO.getUserUsername().startsWith(IMiniappUserService.MINIAPP_RANDOM_USER_PREFIX)) {
            isRandomUsername = ISystemConstant.IS_TRUE_INT;
        }
        return getToken(userPO) + "_" + isRandomUsername;
    }
}
