package com.red.circle.other.infra.database.rds.service.approval.impl;

import com.google.common.collect.Lists;
import com.red.circle.common.business.core.enums.ApprovalStatusEnum;
import com.red.circle.common.business.core.enums.DataApprovalTypeEnum;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.framework.mybatis.constant.PageConstant;
import com.red.circle.framework.mybatis.convertor.MybatisConvertor;
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
import com.red.circle.other.infra.database.rds.dao.approval.ApprovalUserSettingDataDAO;
import com.red.circle.other.infra.database.rds.entity.approval.ApprovalUserSettingData;
import com.red.circle.other.infra.database.rds.service.approval.ApprovalUserSettingDataService;
import com.red.circle.other.inner.model.cmd.approval.ApprovalDataCmd;
import com.red.circle.other.inner.model.cmd.approval.ApprovalProfileDescQryCmd;
import com.red.circle.other.inner.model.cmd.approval.ApprovalUserProfileQryCmd;
import com.red.circle.other.inner.model.dto.approval.ApprovalUserProfileDTO;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 审批用户设置资料信息 服务实现类
 * </p>
 *
 * @author houyong
 * @since 2020-12-09
 */
@Service
@RequiredArgsConstructor
public class ApprovalUserSettingDataServiceImpl extends
    BaseServiceImpl<ApprovalUserSettingDataDAO, ApprovalUserSettingData> implements
    ApprovalUserSettingDataService {

  private final ApprovalUserSettingDataDAO approvalUserSettingDataDAO;

  @Override
  public void updateApprovalStatus(Long userId, DataApprovalTypeEnum approvalType,
      ApprovalStatusEnum status, Long approvalUser) {
    update().set(ApprovalUserSettingData::getApproveStatus, status)
        .set(ApprovalUserSettingData::getUpdateUser, approvalUser)
        .eq(ApprovalUserSettingData::getApproveType, approvalType)
        .eq(ApprovalUserSettingData::getUserId, userId)
        .execute();
  }

  @Override
  public void updateStatus(ApprovalDataCmd cmd) {
    update().set(ApprovalUserSettingData::getApproveStatus, cmd.getApprovalStatus())
        .set(ApprovalUserSettingData::getUpdateUser, cmd.getApprovalUserId())
        .eq(ApprovalUserSettingData::getApproveType, cmd.getApprovalType())
        .in(ApprovalUserSettingData::getUserId, cmd.getUserIds())
        .execute();
  }

  @Override
  public void saveOrUpdateApproval(Long userId, String sysOrigin,
      DataApprovalTypeEnum approveType) {
    saveOrUpdateApproval(userId, sysOrigin, approveType, initialApprovalStatus(approveType));
  }

  @Override
  public void saveOrUpdateApproval(Long userId, String sysOrigin,
      DataApprovalTypeEnum approveType, ApprovalStatusEnum approvalStatusEnum) {
    if (existsByUserApprovalType(userId, approveType)) {
      update().set(ApprovalUserSettingData::getApproveStatus, approvalStatusEnum)
          .set(ApprovalUserSettingData::getMachineLabel, StringUtils.EMPTY)
          .eq(ApprovalUserSettingData::getUserId, userId)
          .eq(ApprovalUserSettingData::getApproveType, approveType)
          .last(PageConstant.LIMIT_ONE)
          .execute();
      return;
    }

    try {
      save(new ApprovalUserSettingData()
          .setUserId(userId)
          .setSysOrigin(sysOrigin)
          .setApproveType(approveType.name())
          .setApproveStatus(approvalStatusEnum.name())
          .setMachineLabel(StringUtils.EMPTY)
          .setNotPassSize(0)
      );
    } catch (DuplicateKeyException ignore) {
      // ignore
    }
  }

  @Override
  public void saveApproval(Long userId, String sysOrigin, DataApprovalTypeEnum approveType,
      ApprovalStatusEnum approvalStatusEnum) {
    save(new ApprovalUserSettingData()
        .setSysOrigin(sysOrigin)
        .setUserId(userId)
        .setApproveType(approveType.name())
        .setApproveStatus(approvalStatusEnum.name())
        .setNotPassSize(0)
    );
  }

  @Override
  public void saveBatchApproval(Long userId, String sysOriginPlatform, List<DataApprovalTypeEnum> approveTypes) {
    saveBatch(approveTypes.stream().map(approvalTypeEnum -> {
      ApprovalUserSettingData approvalUserSettingData = new ApprovalUserSettingData()
          .setSysOrigin(sysOriginPlatform)
          .setUserId(userId)
          .setApproveType(approvalTypeEnum.name())
          .setApproveStatus(initialApprovalStatus(approvalTypeEnum).name())
          .setMachineLabel("")
          .setNotPassSize(0);
      approvalUserSettingData.setCreateTime(TimestampUtils.now());
      approvalUserSettingData.setUpdateTime(TimestampUtils.now());
      return approvalUserSettingData;
    }).toList());
  }

  @Override
  public void incrNotPassSize(Long userId, DataApprovalTypeEnum approveType) {
    update().set(ApprovalUserSettingData::getNotPassSize, "not_pass_size+1")
        .eq(ApprovalUserSettingData::getUserId, userId)
        .eq(ApprovalUserSettingData::getApproveType, approveType)
        .last(PageConstant.LIMIT_ONE)
        .execute();
  }

  @Override
  public boolean updateApprovalStatusMachineLabel(Long userId, ApprovalStatusEnum approvalStatus,
      DataApprovalTypeEnum approveType, String label) {
    return update().set(ApprovalUserSettingData::getMachineLabel, label)
        .set(ApprovalUserSettingData::getApproveStatus, approvalStatus)
        .eq(ApprovalUserSettingData::getUserId, userId)
        .eq(ApprovalUserSettingData::getApproveType, approveType)
        .last(PageConstant.LIMIT_ONE)
        .execute();
  }

  @Override
  public boolean isPass(Long userId, DataApprovalTypeEnum approvalType) {
    return Optional.ofNullable(
            query().select(ApprovalUserSettingData::getId)
                .eq(ApprovalUserSettingData::getUserId, userId)
                .eq(ApprovalUserSettingData::getApproveType, approvalType)
                .eq(ApprovalUserSettingData::getApproveStatus, ApprovalStatusEnum.PASS)
                .last(PageConstant.LIMIT_ONE)
                .getOne()
        ).map(approvalUserSettingData -> Objects.nonNull(approvalUserSettingData.getApproveStatus()))
        .orElse(Boolean.FALSE);
  }

  @Override
  public List<ApprovalUserSettingData> getListByUserId(Long userId) {
    if (Objects.isNull(userId)) {
      return null;
    }
    return query()
            .eq(ApprovalUserSettingData::getUserId, userId)
            .list();
  }

  @Override
  public boolean isNoneOrNotPass(Long userId, DataApprovalTypeEnum approvalType) {
    return Optional.ofNullable(
            query().select(ApprovalUserSettingData::getApproveStatus)
                .eq(ApprovalUserSettingData::getUserId, userId)
                .eq(ApprovalUserSettingData::getApproveType, approvalType)
                .last(PageConstant.LIMIT_ONE)
                .getOne()
        ).map(approvalUserSettingData ->
            Objects
                .equals(approvalUserSettingData.getApproveStatus(), ApprovalStatusEnum.NOT_PASS.name())
                || Objects
                .equals(approvalUserSettingData.getApproveStatus(), ApprovalStatusEnum.NONE.name()))
        .orElse(Boolean.TRUE);
  }

  private Boolean existsByUserApprovalType(Long userId, DataApprovalTypeEnum approveType) {
    return Optional.ofNullable(
            query().select(ApprovalUserSettingData::getId)
                .eq(ApprovalUserSettingData::getApproveType, approveType.name())
                .eq(ApprovalUserSettingData::getUserId, userId)
                .last(PageConstant.LIMIT_ONE)
                .getOne()
        ).map(approvalUserSettingData -> Objects.nonNull(approvalUserSettingData.getId()))
        .orElse(Boolean.FALSE);
  }

  private ApprovalStatusEnum initialApprovalStatus(DataApprovalTypeEnum approveType) {
    if (Objects.isNull(approveType)) {
      return ApprovalStatusEnum.PENDING;
    }

    return switch (approveType) {
      case NICKNAME, AVATAR, PHOTO_WALL, ROOM_NICKNAME, ROOM_AVATAR, ROOM_NOTICE,
          PROFILE_DESC, FAMILY_AVATAR, FAMILY_NICKNAME, FAMILY_NOTICE, DYNAMIC_CONTENT,
          TEAM_AVATAR, TEAM_NICKNAME, BACKGROUND_PHOTO, PERSONAL_PHOTO ->
          ApprovalStatusEnum.PASS;
      default -> ApprovalStatusEnum.PENDING;
    };
  }


  @Override
  public void deleteFamilyApproval(Long userId) {
    if (Objects.isNull(userId)) {
      return;
    }
    delete()
        .eq(ApprovalUserSettingData::getUserId, userId)
        .in(ApprovalUserSettingData::getApproveType,
            Lists.newArrayList(
                DataApprovalTypeEnum.FAMILY_AVATAR.name(),
                DataApprovalTypeEnum.FAMILY_NICKNAME.name(),
                DataApprovalTypeEnum.FAMILY_NOTICE.name()
            )
        ).execute();
  }

  @Override
  public PageResult<ApprovalUserSettingData> pageFamilyApproval(ApprovalProfileDescQryCmd query) {
    return query()
        .eq(ApprovalUserSettingData::getApproveType, query.getApproveType())
        .eq(ApprovalUserSettingData::getApproveStatus, query.getApproveStatus())
        .eq(Objects.nonNull(query.getUserId()), ApprovalUserSettingData::getUserId,
            query.getUserId())
        .likeRight(StringUtils.isNotBlank(query.getSysOrigin()),
            ApprovalUserSettingData::getSysOrigin,
            query.getSysOrigin())
        .ge(Objects.nonNull(query.getStartTime()), ApprovalUserSettingData::getUpdateTime,
            query.getStartTime())
        .lt(Objects.nonNull(query.getEndTime()), ApprovalUserSettingData::getUpdateTime,
            query.getEndTime())
        .page(query.getPageQuery());
  }

  @Override
  public PageResult<ApprovalUserProfileDTO> pageUserProfileApproval(
      ApprovalUserProfileQryCmd query) {
    return MybatisConvertor.toPageResult(approvalUserSettingDataDAO.pageUserProfileApproval(
        MybatisConvertor.toPage(query.getPageQuery()), query));
  }
}
