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 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.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * <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;

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

    @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, existUserInfoVo.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();
        if (StringUtils.isEmpty(beforeNickname) || !beforeNickname.equals(parameter.getNickname())) {
            // IM设置推送昵称
            easemobUtil.settingNoticeNickname(parameter.getNickname(), existUserInfoVo.getUid());
        }

        existUserInfoVo.setAvatar(parameter.getAvatar());
        existUserInfoVo.setBackground(parameter.getBackground());
        existUserInfoVo.setNickname(parameter.getNickname());
        existUserInfoVo.setSignature(parameter.getSignature());
//        existUserInfoVo.setAvatar(StringUtils.isEmpty(existUserInfoVo.getAvatar()) ? AdamConst.DEF_URL_AVATAR : existUserInfoVo.getAvatar());
//        existUserInfoVo.setBackground(StringUtils.isEmpty(existUserInfoVo.getBackground()) ? AdamConst.DEF_URL_BACKGROUND : existUserInfoVo.getBackground());
//        existUserInfoVo.setNickname(existUserInfoVo.getNickname());
//        existUserInfoVo.setSignature(existUserInfoVo.getSignature());
        existUserInfoVo.setSex(parameter.getSex());
        existUserInfoVo.setBirthday(parameter.getBirthday());
        existUserInfoVo.setArea(parameter.getArea());
        existUserInfoVo.setTagMe(tagMe);
        existUserInfoVo.setUpdatedAt(LocalDateTime.now());
        existUserInfoVo.setIsComplete(isComplete);

        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()))) {
            // 同步`service-chime`
            ResponseDto<String> chimeRegisterRstFlg = null;
            try {
                chimeRegisterRstFlg = feignAdamChimeClient.registerForUser(
                        existUserInfoVo.getUid(), sexStr, tagMeStr,syncChimeRegisterFlg ? "CREATE" : "UPDATE"
                );
            } catch (Exception e) {
                log.error("同步`chime`用户标签信息异常", e);
            }
            log.debug("同步`chime`用户标签信息结果:{}", JsonUtils.toJson(chimeRegisterRstFlg));
        }

        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> updateUserObjs = CollectionUtil.linkedListObjectArr(),
                updateUserInfoObjs = 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()
                }
        );
        log.debug("#SQL.GET耗时:{}ms", System.currentTimeMillis() - s);

        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, initUserBusiAcctObjs)
            );
        } else {
            queueUtils.sendMsgByRedis(MQConst.AdamQueue.SQL_UCENTER.getKey(),
                    SqlMapping.gets(toMqSqls, updateUserObjs, updateUserInfoObjs)
            );
        }
        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;
    }
}
