package com.red.circle.other.app.command.user;

import cn.hutool.core.util.ObjectUtil;
import com.red.circle.common.business.core.ImageSizeConst;
import com.red.circle.common.business.core.SensitiveWordFilter;
import com.red.circle.common.business.core.constant.KeywordConstant;
import com.red.circle.common.business.core.enums.DataApprovalTypeEnum;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.external.inner.endpoint.oss.OssServiceClient;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.cmd.user.user.UserProfileModifyCmd;
import com.red.circle.other.domain.gateway.approval.ProfileApprovalGateway;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.approval.ProfileApprovalContent;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.cache.service.cp.CpRelationshipCacheService;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.rds.entity.sys.SysCountryCode;
import com.red.circle.other.infra.database.rds.entity.user.user.BaseInfo;
import com.red.circle.other.infra.database.rds.service.sys.SysCountryCodeService;
import com.red.circle.other.infra.database.rds.service.user.user.BaseInfoService;
import com.red.circle.other.inner.asserts.DynamicErrorCode;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.other.domain.enums.PhotoAuditStatus;
import com.red.circle.other.inner.model.dto.user.PhotoItem;
import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 修改用户资料.
 *
 * @author pengliang on 2020/11/12
 */
@Component
@RequiredArgsConstructor
public class UpdateUserProfileCmdExe {

  private static final Logger log = LoggerFactory.getLogger(UpdateUserProfileCmdExe.class);
  private final OssServiceClient ossServiceClient;
  private final UserProfileGateway userProfileGateway;
  private final RedisService redisService;
  private final BaseInfoService baseInfoService;
  private final SysCountryCodeService sysCountryCodeService;
  private final ProfileApprovalGateway profileApprovalGateway;
  private final UserProfileAppConvertor userProfileAppConvertor;
  private final RoomProfileManagerService roomProfileManagerService;
  private final CpRelationshipCacheService cpRelationshipCacheService;

  public UserProfileDTO execute(UserProfileModifyCmd cmd) {
    //敏感词
    if(ObjectUtil.isNotEmpty(cmd.getUserNickname())){
      ResponseAssert.isFalse(DynamicErrorCode.SENSITIVE_WORD_ERROR, SensitiveWordFilter.checkSensitiveWord(cmd.getUserNickname()));
    }
    userProfileGateway.removeCacheAll(cmd.requiredReqUserId());
    UserProfile userProfile = userProfileGateway.getByUserId(cmd.requiredReqUserId());
    ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, userProfile);
    if (cmd.getCountryId() != null && cmd.getCountryId() > 0) {
      // 更改国家 查询redis是否修改过
      String isUpdateCountry = redisService.getString("IS_UPDATE_COUNTRY:" + cmd.requiredReqUserId());
      if (StringUtils.isNotBlank(isUpdateCountry) && "1".equals(isUpdateCountry)) {
        return userProfileAppConvertor.toUserProfileDTO(userProfile);
      }
    }
    if (StringUtils.isNotBlank(cmd.getUserAvatar())) {
      cmd.setUserAvatar(ossServiceClient.processImgSaveAsCompressZoom(cmd.getUserAvatar(),
          ImageSizeConst.COVER_HEIGHT).getBody()
      );
    }

    UserProfile updateUserProfile = userProfileAppConvertor.toUserProfile(cmd);
    ResponseAssert.notNull(CommonErrorCode.UPDATE_FAILURE, updateUserProfile);
    updateUserProfile.setId(userProfile.getId());

    // 处理背景照片：如果传入非null，则更新（包括空列表）
    if (cmd.getBackgroundPhotos() != null) {
      updateUserProfile.setBackgroundPhotos(
          CollectionUtils.isNotEmpty(cmd.getBackgroundPhotos())
              ? userProfileAppConvertor.toPhotoItems(cmd.getBackgroundPhotos())
              : CollectionUtils.newArrayList()
      );
    }

    // 处理个人形象照片：如果传入非null，则更新（包括空列表）
    if (cmd.getPersonalPhotos() != null) {
      updateUserProfile.setPersonalPhotos(
          CollectionUtils.isNotEmpty(cmd.getPersonalPhotos()) 
              ? userProfileAppConvertor.toPhotoItems(cmd.getPersonalPhotos()) 
              : CollectionUtils.newArrayList()
      );
    }

    updateUserProfile.setUserNickname(
        StringUtils.isNotBlank(updateUserProfile.getUserNickname())
            ? KeywordConstant.filter(updateUserProfile.getUserNickname())
            : null);

    updateUserProfile.setAge(cmd.age());

    // 计算年龄
    processAge(updateUserProfile);

    processCountry(cmd, userProfile);
    syncCountry(updateUserProfile, userProfile);

    // 处理照片状态
    processPhotoStatus(updateUserProfile.getBackgroundPhotos(), userProfile.getBackgroundPhotos());
    processPhotoStatus(updateUserProfile.getPersonalPhotos(), userProfile.getPersonalPhotos());

    userProfileGateway.updateSelectiveById(updateUserProfile);

    // 同步修改房间国家
    if (Objects.nonNull(userProfile.getCountryCode()) && Objects.nonNull(
        userProfile.getCountryName())) {
      // 修改个人信息
      updateBaseInfo(cmd, userProfile);
      roomProfileManagerService.updateUserCountry(userProfile.getId(),
          userProfile.getCountryCode(),
          userProfile.getCountryName());
      // 清除缓存
      userProfileGateway.removeCacheAll(cmd.requiredReqUserId());
    }

    syncProperty(userProfile, cmd);
    log.warn("cmd： {},{}", cmd, userProfile);
    updateUserProfile.setOriginSys(cmd.requireReqSysOrigin());
    submitApproval(updateUserProfile, userProfile);
    if (cmd.getCountryId() != null && cmd.getCountryId() > 0) {
      // 更改国家 设置redis表示已修改 两年过期
      redisService.setString("IS_UPDATE_COUNTRY:" + cmd.requiredReqUserId(), "1", 730, TimeUnit.DAYS);
    }

    cpRelationshipCacheService.remove(Collections.singletonList(cmd.requiredReqUserId()));

    return userProfileAppConvertor.toUserProfileDTO(userProfile);
  }

  private void updateBaseInfo(UserProfileModifyCmd cmd, UserProfile userProfile) {
    BaseInfo baseInfo = new BaseInfo();
    baseInfo.setId(cmd.requiredReqUserId());
    baseInfo.setCountryId(userProfile.getCountryId());
    baseInfo.setCountryCode(userProfile.getCountryCode());
    baseInfo.setCountryName(userProfile.getCountryName());
    baseInfoService.updateSelectiveById(baseInfo);
  }

  private void syncCountry(UserProfile updateUserProfile, UserProfile userProfile) {
    if (Objects.isNull(updateUserProfile) || Objects.isNull(userProfile)) {
      return;
    }
    if (Objects.nonNull(userProfile.getCountryId())) {
      updateUserProfile.setCountryId(userProfile.getCountryId());
    }
    if (StringUtils.isNotBlank(userProfile.getCountryCode())) {
      updateUserProfile.setCountryCode(userProfile.getCountryCode());
    }
    if (StringUtils.isNotBlank(userProfile.getCountryName())) {
      updateUserProfile.setCountryName(userProfile.getCountryName());
    }
  }

  private void submitApproval(UserProfile updateUserProfile, UserProfile originalUserProfile) {
    List<ProfileApprovalContent> approvalParam = CollectionUtils.newArrayList();
    if (StringUtils.isNotBlank(updateUserProfile.getUserAvatar())) {
      approvalParam.add(
          new ProfileApprovalContent()
              .setBeUserId(updateUserProfile.getId())
              .setSysOrigin(updateUserProfile.getOriginSys())
              .setApprovalType(DataApprovalTypeEnum.AVATAR)
              .addContent(
                  updateUserProfile.getId(),
                  updateUserProfile.getUserAvatar()
              )
      );
    }

    if (StringUtils.isNotBlank(updateUserProfile.getUserNickname())) {
      approvalParam.add(
          new ProfileApprovalContent()
              .setBeUserId(updateUserProfile.getId())
              .setSysOrigin(updateUserProfile.getOriginSys())
              .setApprovalType(DataApprovalTypeEnum.NICKNAME)
              .addContent(
                  updateUserProfile.getId(),
                  updateUserProfile.getUserNickname()
              )
      );
    }
    addNewPhotoApproval(approvalParam, updateUserProfile, updateUserProfile.getBackgroundPhotos(),
        originalUserProfile.getBackgroundPhotos(), DataApprovalTypeEnum.BACKGROUND_PHOTO);
    addNewPhotoApproval(approvalParam, updateUserProfile, updateUserProfile.getPersonalPhotos(),
        originalUserProfile.getPersonalPhotos(), DataApprovalTypeEnum.PERSONAL_PHOTO);

    if (CollectionUtils.isNotEmpty(approvalParam)) {
      profileApprovalGateway.submitApprovalBatch(approvalParam);
    }

  }

  private void addNewPhotoApproval(List<ProfileApprovalContent> approvalParam,
      UserProfile updateUserProfile, List<PhotoItem> newPhotos, List<PhotoItem> originalPhotos,
      DataApprovalTypeEnum approvalType) {
    if (CollectionUtils.isEmpty(newPhotos)) {
      return;
    }

    for (PhotoItem photo : newPhotos) {
      if (StringUtils.isBlank(photo.getUrl()) || !isNewPhoto(photo, originalPhotos)) {
        continue;
      }
      approvalParam.add(
          new ProfileApprovalContent()
              .setBeUserId(updateUserProfile.getId())
              .setSysOrigin(updateUserProfile.getOriginSys())
              .setApprovalType(approvalType)
              .addContent(updateUserProfile.getId(), photo.getUrl())
      );
    }
  }

  private boolean isNewPhoto(PhotoItem photo, List<PhotoItem> originalPhotos) {
    return CollectionUtils.isEmpty(originalPhotos)
        || originalPhotos.stream().noneMatch(item -> Objects.equals(item.getUrl(), photo.getUrl()));
  }

  private void syncProperty(UserProfile oldProfile, UserProfileModifyCmd cmd) {

    if (StringUtils.isNotBlank(cmd.getUserNickname())) {
      oldProfile.setUserNickname(cmd.getUserNickname());
    }

    if (StringUtils.isNotBlank(cmd.getUserAvatar())) {
      oldProfile.setUserAvatar(cmd.getUserAvatar());
    }

    if (cmd.age() > 0) {
      oldProfile.setAge(cmd.age());
      oldProfile.setBornYear(cmd.getBornYear());
      oldProfile.setBornMonth(cmd.getBornMonth());
      oldProfile.setBornDay(cmd.getBornDay());
    }

    if (Objects.nonNull(cmd.getUserSex())) {
      oldProfile.setUserSex(cmd.getUserSex());
    }

  }

  private void processAge(UserProfile userProfile) {

    if (Objects.nonNull(userProfile.getAge()) && userProfile.getAge() > 0) {
      return;
    }

    userProfile.setAge(null);
    userProfile.setBornYear(null);
    userProfile.setBornMonth(null);
    userProfile.setBornDay(null);
  }

  private void processCountry(UserProfileModifyCmd cmd, UserProfile baseInfo) {
    if (Objects.nonNull(cmd.getCountryId()) && !Objects.equals(baseInfo.getCountryId(),
        cmd.getCountryId())) {
      // 设置新国家
      SysCountryCode sysCountryCode = sysCountryCodeService.getById(cmd.getCountryId());
      if (Objects.nonNull(sysCountryCode)) {
        baseInfo.setCountryCode(sysCountryCode.getAlphaTwo());
        baseInfo.setCountryName(sysCountryCode.getCountryName());
        baseInfo.setCountryId(sysCountryCode.getId());
        return;
      }
    }

    baseInfo.setCountryCode(null);
    baseInfo.setCountryName(null);
    baseInfo.setCountryId(null);
  }

  /**
   * 处理照片状态：新照片默认先通过，机审回写最终状态，已存在照片保持原状态.
   */
  private void processPhotoStatus(List<PhotoItem> newPhotos, List<PhotoItem> originalPhotos) {
    if (newPhotos == null) {
      return;
    }
    
    if (newPhotos.isEmpty()) {
      return;
    }
    
    for (PhotoItem photo : newPhotos) {
      boolean isNew = CollectionUtils.isEmpty(originalPhotos)
          || originalPhotos.stream().noneMatch(p -> Objects.equals(p.getUrl(), photo.getUrl()));
      
      if (isNew) {
        photo.setStatus(PhotoAuditStatus.APPROVED.getCode());
      } else {
        originalPhotos.stream()
            .filter(p -> Objects.equals(p.getUrl(), photo.getUrl()))
            .findFirst()
            .ifPresent(p -> photo.setStatus(p.getStatus()));
      }
    }
  }

}
