package com.xunwang.ucenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.xunwang.commonutils.JwtUtils;
import com.xunwang.commonutils.RandomNameUtils;
import com.xunwang.commonutils.RedisIdWorker;
import com.xunwang.commonutils.ResultCode;
import com.xunwang.servicebase.exception.XunwangException;
import com.xunwang.ucenter.entity.MpOpenidUid;
import com.xunwang.ucenter.mapper.MiniProgramOpenidUidMapper;
import com.xunwang.ucenter.service.MiniProgramOpenidUidService;
import com.xunwang.ucenter.utils.HttpClientUtils;
import com.xunwang.ucenter.utils.LocationUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Long
 * @since 2022-11-09
 */
@Service
public class MiniProgramOpenidUidServiceImpl extends ServiceImpl<MiniProgramOpenidUidMapper, MpOpenidUid> implements MiniProgramOpenidUidService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private RedisIdWorker redisIdWorker;

    /**
     * 获取用户openid，unionid等
     * @param appid
     * @param secret
     * @param code
     * @param grant_type
     * @return
     */
    @Override
    public Map<String, String> getOpenId(HttpServletRequest request, String appid, String secret, String code, String grant_type) throws Exception {
        // 调用微信登录接口
        String baseCode2SessionUrl = "https://api.weixin.qq.com/sns/jscode2session" + "?appid=%s" + "&secret=%s" + "&js_code=%s" + "&grant_type=%s";
        String code2SessionUrl = String.format(baseCode2SessionUrl, appid, secret, code, grant_type);
        String result = HttpClientUtils.get(code2SessionUrl);

        // 解析json字符串
        Gson gson = new Gson();
        HashMap<String, String> hashMap = gson.fromJson(result, HashMap.class);

        // 获取openid、unionid等
        String openid = (String) hashMap.get("openid");
        String unionid = (String) hashMap.get("unionid");

        // 获取ip地址
        String ip = getIp(request);
        String city = LocationUtils.getRegionFromIp(ip);

        MpOpenidUid user = baseMapper.selectOne(new QueryWrapper<MpOpenidUid>().eq("openid", openid));
        String alias = "";
        String avatar = "";
        String formatUid = "";
        if (user == null) {
            // 新用户注册
            avatar = "https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0";
            user = new MpOpenidUid();
            alias = RandomNameUtils.generateName();
            long uid = redisIdWorker.nextId("uid");
            formatUid = String.format("%08x", uid);

            user.setOpenid(openid).setUnionid(unionid).setAlias(alias).setCity(city).setUid(formatUid).setAvatar(avatar);
            baseMapper.insert(user);

        } else {
            // 老用户登录
            alias = user.getAlias();
            avatar = user.getAvatar();
            formatUid = user.getUid();

            user.setLastLoginDatetime(null).setCity(city);
            baseMapper.updateById(user);
        }

        // 将用户信息生成token字符串
        String token = JwtUtils.getJwtToken(user.getUid(), openid);

        // 返回信息
        HashMap<String, String> map = new HashMap<>();
        map.put("token", token);
        map.put("alias", alias);
        map.put("city", city);
        map.put("avatar", avatar);
        map.put("uid", formatUid);

        return map;
    }

    /**
     * 修改微信昵称
     * @param uid
     * @param alias
     * @return
     */
    @Override
    public void editAlias(String uid, String alias, String avatar) {
        MpOpenidUid mpOpenidUid = new MpOpenidUid();
        mpOpenidUid.setAlias(alias);
        mpOpenidUid.setUid(uid);
        mpOpenidUid.setAvatar(avatar);
        int count = baseMapper.updateById(mpOpenidUid);
        if (count != 1) {
            throw new XunwangException(ResultCode.ERROR, "更新昵称失败！");
        }
    }

    /**
     * 获取用户手机号
     * @param uid
     * @param code
     * @throws Exception
     */
    @Override
    public String getUserPhone(String uid, String code) throws Exception {
        // 调用微信获取电话接口
        String basePhoneUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber" + "?access_token=%s";
        if (!redisTemplate.hasKey("access_token")) {
            throw new XunwangException(ResultCode.ERROR, "access_token过期！");
        }
        String access_token = (String) redisTemplate.opsForValue().get("access_token");
        String formatPhoneUrl = String.format(basePhoneUrl, access_token);

        // 传入请求体
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("code", code);
        String result = HttpClientUtils.postParameters(formatPhoneUrl, jsonObject.toString());

        // 解析结果
        Gson gson = new Gson();
        HashMap<String, Object> hashMap = gson.fromJson(result, HashMap.class);
        Map phone_info = (Map)hashMap.get("phone_info");

        String phone = phone_info.get("phoneNumber").toString();

        // 存入数据库
        QueryWrapper<MpOpenidUid> queryWrapper = new QueryWrapper();
        queryWrapper.eq("uid", uid);
        MpOpenidUid mpOpenidUid = baseMapper.selectOne(queryWrapper);
        mpOpenidUid.setPhone(phone);

        int i = this.baseMapper.updateById(mpOpenidUid);
        if (i != 1) {
            throw new XunwangException(ResultCode.ERROR, "更新手机号失败");
        }

        return phone;
    }

    /**
     * 获取当前请求的IP地址
     * @param request
     * @return
     */
    private String getIp(HttpServletRequest request) {
        String ip = "";
        if (request.getHeader("x-forwarded-for") == null) {
            ip = request.getRemoteAddr();
        } else {
            ip = request.getHeader("x-forwarded-for");
        }
        return ip;
    }

}
