package org.jeecg.api.service.impl;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jeecg.api.bean.LoginReq;
import org.jeecg.api.service.AppletLoginService;
import org.jeecg.api.untils.HttpConf;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.hanHaiMember.entity.HanHaiMember;
import org.jeecg.modules.hanHaiMember.service.IHanHaiMemberService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author lzx
 * @Date 2022-05-13 15:55
 **/
@Slf4j
@Service
@SuppressWarnings("all")
public class AppletLoginServiceImpl implements AppletLoginService {

    @Value("${wechat-dm.mpAppId}")
    private String mpAppId;
    @Value("${wechat-dm.mpAppSecret}")
    private String mpAppSecret;

    @Resource
    private IHanHaiMemberService memberService;

    @Resource
    private RedisUtil redisUtil;
    @Resource
    private HttpConf httpConf;




    /**
     * 微信小程序登录接口
     * @param loginReq
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    public Result<Object> appletLogin(LoginReq loginReq) {

        //传入数据：
        log.info("小程序登录参数：{}", loginReq);
        //传入邀请者标识
        log.info("小程序邀请者标识：" + loginReq.getShareId());



        Result<Object> result = new Result<>();
        Map<String, Object> map = new HashMap<>();
        if (StringUtils.isBlank(loginReq.getCode())) {
            throw new JeecgBootException("小程序code为空");
        }
        String loginUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + mpAppId + "&secret=" + mpAppSecret+ "&js_code=" + loginReq.getCode() + "&grant_type=authorization_code";
        //使用工具类
        JSONObject json_test = httpConf.getJSONObject(loginUrl);
        String wxOpenid = json_test.getString("openid");
        String sessionKey = json_test.getString("session_key");
        if (StringUtils.isBlank(wxOpenid)) {
            throw new JeecgBootException("未获取到openid");
        }

        HanHaiMember member = memberService.lambdaQuery().eq(HanHaiMember::getAppletOpenid,wxOpenid).one();
        if (member == null) {
            //如果user等于null说明该用户第一次登录，数据库没有该用户信息。
            loginReq.setOpenid(wxOpenid);
            loginReq.setSession_key(sessionKey);
            member = new HanHaiMember();
            member.setSessionKey(sessionKey);
            member.setAppletOpenid(wxOpenid);
            member.setNickName("农闲宝"+System.currentTimeMillis());
            member.setHeadImage(null);
            member.setShareId(loginReq.getShareId());
            member.setVtime(new Date());
            // 生成token返回给小程序端
            String token = JwtUtil.sign(member.getAppletOpenid(), wxOpenid);
            memberService.save(member);
            redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
            // 设置超时时间
            redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 100);
            map.put("userInfo", member);
            map.put("token", token);

            result.setCode(200);
            result.setResult(map);
            return result;
        } else {
//            member.setHeadImage(loginReq.getHeadimgurl());
//            member.setSessionKey(sessionKey);
//            memberService.saveOrUpdate(member);
            // 生成token返回给小程序端
            String token = JwtUtil.sign(member.getAppletOpenid(), wxOpenid);
            redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
            // 设置超时时间
            redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 100);
            map.put("userInfo", member);
            map.put("token", token);
            //用户id做im账号
            result.setResult(map);
            result.setCode(200);
//            result.setMessage(member.getNickName()+"已于"+member.getCreateTime()+"注册成功！请勿重复注册！");
            // 未绑定手机号，跳转授权绑定手机号
//            if (StringUtils.isBlank(member.getPhone())) {
//                result.setMessage("用户未绑定手机号码！需绑定手机号码");
//                result.setCode(905);
//                result.setResult(map);
//                return result;
//            }
        }
        return result;
    }


    /**
     * 微信小程序登录绑定手机号码接口
     * @param loginReq
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Object> bindPhone(LoginReq loginReq) {
        Result<Object> result = new Result<>();
        if (StringUtils.isEmpty(loginReq.getEncryptedData())) {
            result.setCode(500);
            result.setMessage("请授权手机号");
            return result;
        }
        String loginUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + mpAppId + "&secret=" + mpAppSecret+ "&js_code=" + loginReq.getCode() + "&grant_type=authorization_code";
        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;
        try {
            // 创建http GET请求
            HttpGet httpGet = new HttpGet(loginUrl);
            client = HttpClients.createDefault();
            // 执行请求
            response = client.execute(httpGet);
            HttpEntity entity = response.getEntity();//得到返回数据
            String resultStr = EntityUtils.toString(entity);
            JSONObject json_test = JSONObject.parseObject(resultStr);
            String wxOpenid = json_test.getString("openid");
            if (StringUtils.isEmpty(wxOpenid)) {
                return result.error500("未获取到openid");
            }
            String sessionKey = json_test.getString("session_key");
            // 保存sessionKey,用于解析手机号码
            loginReq.setOpenid(wxOpenid);
            loginReq.setSession_key(sessionKey);
            String userPhone = getPhoneNumber(loginReq);
            HanHaiMember one = memberService.lambdaQuery().eq(HanHaiMember::getAppletOpenid, wxOpenid).one();
            if(one!=null){
                return result.OK("请不要重复注册");
            }
            HanHaiMember member = new HanHaiMember();
            member.setSessionKey(sessionKey);
            member.setAppletOpenid(wxOpenid);
            member.setNickName(loginReq.getNickName());
            member.setHeadImage(loginReq.getHeadimgurl());
            member.setPhone(userPhone);


            //判断用户是否存在
            HanHaiMember boolOne = memberService.lambdaQuery().eq(HanHaiMember::getAppletOpenid, wxOpenid).one();
            boolean bool = false;
            if(one != null){
                bool = true;
            }

            if(!bool){
                member.setId(boolOne.getId());
                memberService.updateById(member);
            }else{
                memberService.save(member);
            }



            return result.OK("手机号码绑定成功",member);
        }catch(Exception e) {
            e.printStackTrace();
            return Result.error("操作失败，请联系系统管理员！");
        }

//        String userPhone = getPhoneNumber(loginReq);
//        HanHaiMember one = memberService.lambdaQuery().eq(HanHaiMember::getAppletOpenid, loginReq.getOpenid()).one();
//        if(one!=null){
//            one.setPhone(userPhone);
//            memberService.updateById(one);
//        }
//        if(one==null){
//            return Result.error("未获取到openid");
//        }
//        return Result.OK("获取成功",userPhone);

    }



    /**
     * 解析电话号码
     * @param loginReq
     * @return
     */
    public String getPhoneNumber(LoginReq loginReq) {
        String encryptedData = loginReq.getEncryptedData();
        String session_key = loginReq.getSession_key();
        String iv = loginReq.getIv();
        // 被加密的数据
        byte[] dataByte = Base64.decodeBase64(encryptedData);
        // 加密秘钥
        byte[] keyByte = Base64.decodeBase64(session_key);
        // 偏移量
        byte[] ivByte = Base64.decodeBase64(iv);
        try {
            // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, "UTF-8");
                JSONObject userPhoneObj = JSONObject.parseObject(result);
                Map<String, Object> userMap = new HashMap<>();
                for (Map.Entry<String, Object> entry : userPhoneObj.entrySet()) {
                    userMap.put(entry.getKey(), entry.getValue());
                }
                // 获取phoneNumber 带区号
                String userPhone = (String) userMap.get("phoneNumber");
                return userPhone;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
