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.constant.AdamConst;
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.ObjectUtil;
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(AdamUserInfoParam parameter) {
        String currentUid = CurrentUtil.getCurrentUid();
        AdamUserInfoVo userInfoVo = adamRdmService.getUserInfoVoByUid(currentUid);

        Integer voIsComplete = userInfoVo.getIsComplete();
        int isComplete = voIsComplete == 0 ? 1 : voIsComplete;

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

        List<AdamTagParentVo> tagMe = parameter.getTagMe();
        String uuid = null, type = null, created = null, modified = null;
        if (!CollectionUtil.isEmpty(tagMe)) {// 标签不为空则注册或更新IM
            if (isComplete == 1) {// 注册IM
                JSONObject jsonObject = null;
                try {
                    // 138cef91a62088bd3ef329fa3a6176cb18a > 138CEF91A62088BD3EF329FA3A6176CB18A > IM@zhengzai
                    String result = easemobUtil.createUser(userInfoVo.getUid(), ppwd, userInfoVo.getNickname());

                    jsonObject = JSONObject.parseObject(result);
                } catch (Exception e) {
                    log.error("###编辑资料:注册IM异常[uid:{},mobile:{}]", userInfoVo.getUid(), userInfoVo.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");
                    created = jsonObject.getString(created);
                    modified = jsonObject.getString("modified");

                    syncChimeRegisterFlg = true;
                }
            } else if (isComplete == 11) {// 同步IM信息
                // TODO: 2021/9/17 暂未接入
            }

            syncChimeFlg = true;
        } else {
            tagMe = userInfoVo.getTagMe();
        }
        AdamTagVo existSex = userInfoVo.getSex();

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

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

        String sexStr = JsonUtils.toJson(userInfoVo.getSex());
        if (syncChimeFlg || null == existSex || !userInfoVo.getSex().getVal().equals(existSex.getVal())) {// 同步`service-chime`
            ResponseDto<String> chimeRegisterRstFlg = null;
            try {
                chimeRegisterRstFlg = feignAdamChimeClient.registerForUser(
                        userInfoVo.getUid(),
                        sexStr,
                        JsonUtils.toJson(tagMe),
                        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[]{1, userInfoVo.getUpdatedAt(), userInfoVo.getUid()});
        toMqSqls.add(SqlMapping.get("adam_user_info.edit"));
        updateUserInfoObjs.add(new Object[]{
                userInfoVo.getNickname(),
                sexStr,
                userInfoVo.getBirthday(),
                userInfoVo.getArea(),
                userInfoVo.getSignature(),
                userInfoVo.getAvatar(),
                userInfoVo.getBackground(),
                JsonUtils.toJson(tagMe),
                userInfoVo.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[]{
                    userInfoVo.getUid(), "IMHX", uuid, type, ppwd, 1, userInfoVo.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(userInfoVo.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);

        s = System.currentTimeMillis();
        queueUtils.sendMsgByRedis(MQConst.AdamQueue.SQL_UCENTER.getKey(),
                SqlMapping.get("adam_user.edit.mobile", mobile, now, uid)
        );
        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.yyyyMMddHHmmssSSS.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;
    }
}
