package com.liquidnet.service.adam.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.common.third.easemob.util.EasemobUtil;
import com.liquidnet.commons.lang.core.JwtValidator;
import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.adam.dto.AdamUserInfoParam;
import com.liquidnet.service.adam.dto.vo.AdamTagParentVo;
import com.liquidnet.service.adam.dto.vo.AdamTagVo;
import com.liquidnet.service.adam.dto.vo.AdamUserInfoVo;
import com.liquidnet.service.adam.service.AdamRdmService;
import com.liquidnet.service.adam.service.IAdamUserInfoService;
import com.liquidnet.service.adam.util.QueueUtils;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.feign.adam.rsc.FeignAdamChimeClient;
import com.liquidnet.service.feign.adam.rsc.FeignAdamStoneClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;

/**
 * <p>
 * 用户信息 服务实现类
 * </p>
 *
 * @author liquidnet
 * @since 2021-05-10
 */
@Slf4j
@Service
public class AdamUserInfoServiceImpl implements IAdamUserInfoService {
    @Autowired
    AdamRdmService adamRdmService;
    @Autowired
    QueueUtils queueUtils;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    JwtValidator jwtValidator;
    @Autowired
    private EasemobUtil easemobUtil;

    @Autowired
    private FeignAdamChimeClient feignAdamChimeClient;
    @Autowired
    private FeignAdamStoneClient feignAdamStoneClient;

    @Value("${liquidnet.reviewer.user-info}")
    private Boolean reviewUserInfo;
    // 用户注册IM的密码
    private static final String ppwd = "138CEF91A62088BD3EF329FA3A6176CB18A";

    private static final Pattern PATTERN_SPACE = Pattern.compile(" ");

    private static final List<String> defaultBackgroundList = Arrays.asList("https://img.zhengzai.tv/other/2021/07/27/150eeb0e20af4fc88e8a1ec57c46c362.png", "https://img.zhengzai.tv/files/2021/01/13/5ffeab3584b7d.png", "http://pic.zhengzai.tv/default/background.png", "http://img.zhengzai.tv/album/20171027/1509106243302.png");

    @Override
//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ResponseDto<AdamUserInfoVo> edit(AdamUserInfoVo existUserInfoVo, AdamUserInfoParam parameter) {
        Integer voIsComplete = existUserInfoVo.getIsComplete();
        int isComplete = voIsComplete == 0 ? 1 : voIsComplete;

        boolean syncChimeFlg = false;// 标识是否需要同步`service-chime`
        boolean syncChimeRegisterFlg = false;// 标识同步`service-chime`是否为首次注册

        List<AdamTagParentVo> tagMe = parameter.getTagMe();
        AdamTagVo beforeSex = existUserInfoVo.getSex();
        String uuid = null, type = null;
        if (!CollectionUtil.isEmpty(tagMe)) {// 标签不为空则注册或更新IM
            if (isComplete == 1) {// 注册IM，参见：https://docs-im.easemob.com/im/server/ready/user
                JSONObject jsonObject = null;
                try {
                    // 138cef91a62088bd3ef329fa3a6176cb18a > 138CEF91A62088BD3EF329FA3A6176CB18A > IM@zhengzai
                    String result = easemobUtil.createUser(existUserInfoVo.getUid(), ppwd, parameter.getNickname());
                    jsonObject = JSONObject.parseObject(result);
                } catch (Exception e) {
                    log.error("###编辑资料:注册IM异常[uid:{},mobile:{}]", existUserInfoVo.getUid(), existUserInfoVo.getMobile());
                }
                if (null == jsonObject || StringUtil.isNotNull(jsonObject.get("error"))) {
                    return ResponseDto.failure(ErrorMapping.get("10014"));
                }
                if (jsonObject.getBooleanValue("activated")) {
                    isComplete = 11;

                    type = jsonObject.getString("type");
                    uuid = jsonObject.getString("uuid");

                    syncChimeRegisterFlg = true;
                }
            }

            syncChimeFlg = true;
        } else {
            tagMe = existUserInfoVo.getTagMe();
        }

        String beforeNickname = existUserInfoVo.getNickname(), nickname = parameter.getNickname();
        if (StringUtils.isEmpty(beforeNickname) || (StringUtils.isNotBlank(nickname) && !beforeNickname.equals(nickname))) {
            // IM设置推送昵称
            easemobUtil.settingNoticeNickname(nickname, existUserInfoVo.getUid());
        }

        existUserInfoVo.setAvatar(parameter.getAvatar());
        existUserInfoVo.setBackground(parameter.getBackground());
        existUserInfoVo.setNickname(nickname);
        existUserInfoVo.setSignature(parameter.getSignature());
        existUserInfoVo.setSex(parameter.getSex());
        existUserInfoVo.setBirthday(parameter.getBirthday());
//        existUserInfoVo.setArea(parameter.getArea());
        existUserInfoVo.setTagMe(tagMe);
        existUserInfoVo.setUpdatedAt(LocalDateTime.now());
        existUserInfoVo.setIsComplete(isComplete);


        boolean updateProvinceCityCountyFlg = false;// 标识更新用户常驻地信息
        String area = parameter.getArea(), province = parameter.getProvince(), city = parameter.getCity(), county = parameter.getCounty();

        if (StringUtils.isNotEmpty(area) && !StringUtils.equals(existUserInfoVo.getArea(), area)) {// 调整前的版本兼容处理，不强更APP
            existUserInfoVo.setArea(area);
            String[] areaArr = PATTERN_SPACE.split(area, 0);
            for (int i = 0; i < areaArr.length; i++) {
                String areaTmp = areaArr[i];
                if (StringUtils.isEmpty(areaTmp) || areaTmp.trim().length() <= 1) {
                    continue;
                }
                updateProvinceCityCountyFlg = true;
                switch (i) {
                    case 0:
                        existUserInfoVo.setProvince(areaTmp);
                        break;
                    case 1:
                        existUserInfoVo.setCity(areaTmp);
                        break;
                    case 2:
                        existUserInfoVo.setCounty(areaTmp);
                        break;
                }
            }
        }
        if (StringUtils.isNotBlank(province) && StringUtils.isNotBlank(city) && StringUtils.isNotBlank(county)) {// 调整后的版本
            if (!StringUtils.equals(existUserInfoVo.getProvince(), province)
                    || !StringUtils.equals(existUserInfoVo.getCity(), city) || !StringUtils.equals(existUserInfoVo.getCounty(), county)
            ) {
                updateProvinceCityCountyFlg = true;
                existUserInfoVo.setProvince(province);
                existUserInfoVo.setCity(parameter.getCity());
                existUserInfoVo.setCounty(parameter.getCounty());
                existUserInfoVo.setArea(province.concat("-").concat(city).concat("-").concat(county));
            }
        }


        long s = System.currentTimeMillis();
        adamRdmService.setUserInfoVoByUid(existUserInfoVo.getUid(), existUserInfoVo);
        log.debug("#RDS耗时:{}ms", System.currentTimeMillis() - s);

        String sexStr = JsonUtils.toJson(existUserInfoVo.getSex());
        String tagMeStr = JsonUtils.toJson(tagMe);
        if (syncChimeFlg || null == beforeSex || (null != parameter.getSex() && !parameter.getSex().getVal().equals(beforeSex.getVal()))) {
            ResponseDto<String> chimeRegisterRstFlg = null;
            try {// 同步`service-chime`
                chimeRegisterRstFlg = feignAdamChimeClient.registerForUser(
                        existUserInfoVo.getUid(), sexStr, tagMeStr, syncChimeRegisterFlg ? "CREATE" : "UPDATE"
                );
            } catch (Exception e) {
                log.error("同步`chime`用户标签信息异常", e);
            }
            if (log.isDebugEnabled()) {
                log.debug("同步`chime`用户标签信息结果:{}", JsonUtils.toJson(chimeRegisterRstFlg));
            }
        }

        try {// 积分处理
            if (null == beforeSex && null != existUserInfoVo.getSex()) {
                // 有效编辑个人信息
                log.info("积分任务5:完善资料:{}-{}", existUserInfoVo.getMobile(), existUserInfoVo.getUid());
                feignAdamStoneClient.doTaskInner(5, existUserInfoVo.getUid());
            }
            if (StringUtils.isNotBlank(existUserInfoVo.getBackground()) && !defaultBackgroundList.contains(existUserInfoVo.getBackground())) {
                // 有效编辑个人照片
                log.info("积分任务6:完善个人照片:{}-{}", existUserInfoVo.getMobile(), existUserInfoVo.getUid());
                feignAdamStoneClient.doTaskInner(6, existUserInfoVo.getUid());
            }
            if (voIsComplete != 11 && existUserInfoVo.getIsComplete() == 11) {
                // 已同步在场信息
                log.info("积分任务8:首次体验在场:{}-{}", existUserInfoVo.getMobile(), existUserInfoVo.getUid());
                feignAdamStoneClient.doTaskInner(8, existUserInfoVo.getUid());
            }
        } catch (Exception e) {
            log.error("同步`stone`用户积分信息异常", e);
        }

        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> updateUserObjs = CollectionUtil.linkedListObjectArr(),
                updateUserInfoObjs = CollectionUtil.linkedListObjectArr(),
                updateUserMobileLocateObjs = CollectionUtil.linkedListObjectArr(),
                initUserBusiAcctObjs = CollectionUtil.linkedListObjectArr();

        s = System.currentTimeMillis();
        toMqSqls.add(SqlMapping.get("adam_user.complete"));
        updateUserObjs.add(new Object[]{existUserInfoVo.getIsComplete(), existUserInfoVo.getUpdatedAt(), existUserInfoVo.getUid()});
        toMqSqls.add(SqlMapping.get("adam_user_info.edit"));
        updateUserInfoObjs.add(new Object[]{
                existUserInfoVo.getNickname(), sexStr, existUserInfoVo.getBirthday(), existUserInfoVo.getArea(),
                existUserInfoVo.getSignature(), existUserInfoVo.getAvatar(), existUserInfoVo.getBackground(), tagMeStr, existUserInfoVo.getUid()
        });
        toMqSqls.add(SqlMapping.get("adam_user_mobile_locate.update_province"));
        if (updateProvinceCityCountyFlg) {
            updateUserMobileLocateObjs.add(new Object[]{
                    existUserInfoVo.getProvince(), existUserInfoVo.getCity(), existUserInfoVo.getCounty(), existUserInfoVo.getUpdatedAt(), existUserInfoVo.getUid()
            });
        }
        toMqSqls.add(SqlMapping.get("adam_user_busi_acct.add"));
        if (syncChimeRegisterFlg) {
            initUserBusiAcctObjs.add(new Object[]{
                    existUserInfoVo.getUid(), "IMHX", uuid, type, ppwd, 1, existUserInfoVo.getUpdatedAt()
            });
        }
        log.debug("#SQL.GET耗时:{}ms", System.currentTimeMillis() - s);
        queueUtils.sendMsgByRedis(MQConst.AdamQueue.SQL_UCENTER.getKey(),
                SqlMapping.gets(toMqSqls, updateUserObjs, updateUserInfoObjs, updateUserMobileLocateObjs, initUserBusiAcctObjs)
        );

//        if (syncChimeRegisterFlg) {
//            toMqSqls.add(SqlMapping.get("adam_user_busi_acct.add"));
//            LinkedList<Object[]> initUserBusiAcctObjs = CollectionUtil.linkedListObjectArr();
//            initUserBusiAcctObjs.add(new Object[]{
//                    existUserInfoVo.getUid(), "IMHX", uuid, type, ppwd, 1, existUserInfoVo.getUpdatedAt()
//            });
//            queueUtils.sendMsgByRedis(MQConst.AdamQueue.SQL_UCENTER.getKey(),
//                    SqlMapping.gets(toMqSqls, updateUserObjs, updateUserInfoObjs, updateUserMobileLocateObjs, initUserBusiAcctObjs)
//            );
//        } else {
//            queueUtils.sendMsgByRedis(MQConst.AdamQueue.SQL_UCENTER.getKey(),
//                    SqlMapping.gets(toMqSqls, updateUserObjs, updateUserInfoObjs, updateUserMobileLocateObjs)
//            );
//        }
        return ResponseDto.success(existUserInfoVo.desensitize(reviewUserInfo));
    }

    @Override
//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public String editMobile(String uid, String mobile) {
        LocalDateTime now = LocalDateTime.now();
        AdamUserInfoVo beforeUserInfoVo = adamRdmService.getUserInfoVoByUid(uid);

        long s = System.currentTimeMillis();
        adamRdmService.delUidByMobile(beforeUserInfoVo.getMobile());
        adamRdmService.setUidByMobile(mobile, uid);
        beforeUserInfoVo.setMobile(mobile);
        beforeUserInfoVo.setUpdatedAt(now);
        adamRdmService.setUserInfoVoByUid(uid, beforeUserInfoVo);
        log.debug("#RDS耗时:{}ms", System.currentTimeMillis() - s);

        log.info("LNS_USER_MDF_MOBILE:[UID={},OLD_MOBILE={},NEW_MOBILE={},CLI_IP={},CLI_SOURCE={}]", uid, beforeUserInfoVo.getMobile(), mobile, CurrentUtil.getCliIpAddr(), CurrentUtil.getHeaderCliSource());

        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> updateUserInfoObjs = CollectionUtil.linkedListObjectArr(),
                updateUserMobileLocateObjs = CollectionUtil.linkedListObjectArr();

        toMqSqls.add(SqlMapping.get("adam_user.edit.mobile"));
        updateUserInfoObjs.add(new Object[]{mobile, now, uid});

        String[] mobileLocateArr = adamRdmService.getMobileLocateArr(mobile);
        toMqSqls.add(SqlMapping.get("adam_user_mobile_locate.modify_mobile"));
        if (null != mobileLocateArr && mobileLocateArr.length > 0) {
            updateUserMobileLocateObjs.add(new Object[]{
                    mobile,
                    mobileLocateArr[0], mobileLocateArr[1], mobileLocateArr[2], mobileLocateArr[3], mobileLocateArr[4],
                    now, uid
            });
        }

        s = System.currentTimeMillis();
        queueUtils.sendMsgByRedis(MQConst.AdamQueue.SQL_UCENTER.getKey(),
                SqlMapping.gets(toMqSqls, updateUserInfoObjs, updateUserMobileLocateObjs)
        );
        log.debug("#MQ耗时:{}ms", System.currentTimeMillis() - s);

        return this.flushSsoProcess(beforeUserInfoVo);
    }

    private String flushSsoProcess(AdamUserInfoVo userInfoVo) {
        Map<String, Object> claimsMap = CollectionUtil.mapStringObject();
        claimsMap.put(CurrentUtil.TOKEN_SUB, userInfoVo.getUid());
        claimsMap.put(CurrentUtil.TOKEN_MOBILE, userInfoVo.getMobile());
        claimsMap.put(CurrentUtil.TOKEN_NICKNAME, userInfoVo.getNickname());
        claimsMap.put(CurrentUtil.TOKEN_TYPE, CurrentUtil.TOKEN_TYPE_VAL_USER);
        claimsMap.put(CurrentUtil.TOKEN_UCREATED, DateUtil.Formatter.yyyyMMddHHmmssTrim.format(userInfoVo.getCreateAt()));

        String token = jwtValidator.create(claimsMap);

        redisUtil.set(
                jwtValidator.getSsoRedisKey().concat(userInfoVo.getUid()),
                DigestUtils.md5DigestAsHex(token.getBytes(StandardCharsets.UTF_8)),
                jwtValidator.getExpireTtl() * 60
        );
        return token;
    }
}
