package com.red.circle.other.app.inner.service.game.impl;

import com.google.common.collect.Lists;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.app.inner.convertor.game.GameLuckyGiftConfigConvertor;
import com.red.circle.other.app.inner.service.game.GameLuckyGiftConfigClientService;
import com.red.circle.other.infra.database.cache.service.other.GameLuckyGiftCacheService;
import com.red.circle.other.infra.database.rds.entity.game.GameLuckyGiftRuleConfig;
import com.red.circle.other.infra.database.rds.entity.game.GameLuckyGiftStandardConfig;
import com.red.circle.other.infra.database.rds.entity.game.LuckyGiftProbability;
import com.red.circle.other.infra.database.rds.entity.game.LuckyGiftProbabilityDetails;
import com.red.circle.other.infra.database.rds.entity.gift.GiftConfig;
import com.red.circle.other.infra.database.rds.service.game.GameLuckyGiftCountService;
import com.red.circle.other.infra.database.rds.service.game.GameLuckyGiftRuleConfigService;
import com.red.circle.other.infra.database.rds.service.game.GameLuckyGiftStandardConfigService;
import com.red.circle.other.infra.database.rds.service.game.LuckyGiftProbabilityDetailsService;
import com.red.circle.other.infra.database.rds.service.game.LuckyGiftProbabilityService;
import com.red.circle.other.infra.database.rds.service.gift.GiftConfigService;
import com.red.circle.other.inner.asserts.GiftErrorCode;
import com.red.circle.other.inner.enums.material.GiftTabEnum;
import com.red.circle.other.inner.model.cmd.game.GameLuckGiftProbabilityConfigQryCmd;
import com.red.circle.other.inner.model.cmd.game.GameLuckGiftRuleConfigQryCmd;
import com.red.circle.other.inner.model.cmd.game.GameLuckGiftStandardConfigQryCmd;
import com.red.circle.other.inner.model.cmd.game.LuckGiftGameCountQryCmd;
import com.red.circle.other.inner.model.cmd.game.LuckGiftGameQryCmd;
import com.red.circle.other.inner.model.dto.game.GameLuckyGiftCountDTO;
import com.red.circle.other.inner.model.dto.game.GameLuckyGiftDTO;
import com.red.circle.other.inner.model.dto.game.GameLuckyGiftProbabilityDTO;
import com.red.circle.other.inner.model.dto.game.GameLuckyGiftProbabilityDetailsDTO;
import com.red.circle.other.inner.model.dto.game.GameLuckyGiftProbabilityInfoDTO;
import com.red.circle.other.inner.model.dto.game.GameLuckyGiftRuleConfigDTO;
import com.red.circle.other.inner.model.dto.game.GameLuckyGiftStandardConfigDTO;
import com.red.circle.other.inner.model.dto.game.LuckyGiftStandardMapDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 幸运礼物奖项配置
 *
 * @author zongpubin on 2024/1/24
 */
@Service
@RequiredArgsConstructor
public class GameLuckyGiftConfigClientServiceImpl implements GameLuckyGiftConfigClientService {

  private static final Logger log = LoggerFactory.getLogger(GameLuckyGiftConfigClientServiceImpl.class);
  private final GiftConfigService giftConfigService;
  private final GameLuckyGiftCacheService gameLuckyGiftCacheService;
  private final GameLuckyGiftCountService gameLuckyGiftCountService;
  private final LuckyGiftProbabilityService luckyGiftProbabilityService;
  private final GameLuckyGiftConfigConvertor gameLuckyGiftConfigConvertor;
  private final GameLuckyGiftRuleConfigService gameLuckyGiftRuleConfigService;
  private final LuckyGiftProbabilityDetailsService luckyGiftProbabilityDetailsService;
  private final GameLuckyGiftStandardConfigService gameLuckyGiftStandardConfigService;

  @Override
  public PageResult<GameLuckyGiftDTO> pageLuckyGiftGameRecord(LuckGiftGameQryCmd query) {
    PageResult<GameLuckyGiftDTO> gameLuckyGiftDTOPageResult = gameLuckyGiftCountService.pageByCondition(query)
            .convert(gameLuckyGiftConfigConvertor::toGameLuckyGiftDTO);
    log.warn("gameLuckyGift ：" + gameLuckyGiftDTOPageResult.getRecords());
    return gameLuckyGiftDTOPageResult;
  }

  @Override
  public GameLuckyGiftCountDTO countLuckyGiftGame(LuckGiftGameCountQryCmd query) {
    return gameLuckyGiftCountService.countLuckyGiftGame(query);
  }

  @Override
  public List<LuckyGiftStandardMapDTO> listProbability(String sysOrigin) {
    Set<Long> activeStandardIds = giftConfigService.listEffectiveLuckyGiftStandardIds(sysOrigin);
    if (CollectionUtils.isEmpty(activeStandardIds)) {
      return Lists.newArrayList();
    }
    List<GameLuckyGiftStandardConfig> luckyGiftStandards = gameLuckyGiftStandardConfigService.getLuckyGiftStandard(
        sysOrigin).stream()
        .filter(luckyGiftStandard -> activeStandardIds.contains(luckyGiftStandard.getId()))
        .collect(Collectors.toList());
    if (CollectionUtils.isEmpty(luckyGiftStandards)) {
      return Lists.newArrayList();
    }
    Map<Long, List<LuckyGiftProbability>> probabilityMap = luckyGiftProbabilityService.getLuckyGiftProbabilityMap(
        luckyGiftStandards.stream().map(GameLuckyGiftStandardConfig::getId).collect(
            Collectors.toSet()));

    List<GameLuckyGiftStandardConfig> standardConfigs = luckyGiftStandards.stream()
        .filter(luckyGiftStandard ->
            CollectionUtils.isNotEmpty(probabilityMap.get(luckyGiftStandard.getId())))
        .collect(Collectors.toList());

    if (CollectionUtils.isEmpty(standardConfigs)) {
      return Lists.newArrayList();
    }

    return standardConfigs.stream().map(standard ->
        new LuckyGiftStandardMapDTO()
            .setValue(standard.getId())
            .setName(standard.getRemarks())).collect(Collectors.toList());

  }

  @Override
  public GameLuckyGiftRuleConfigDTO getLuckyGiftRuleConfig(GameLuckGiftRuleConfigQryCmd query) {
    return gameLuckyGiftConfigConvertor.toGameLuckyGiftRuleConfigDTO(
        gameLuckyGiftRuleConfigService.getLuckyGiftRuleConfig(query.getSysOrigin()));
  }

  @Override
  public void addLuckyGiftRuleConfig(GameLuckyGiftRuleConfigDTO param) {
    GameLuckyGiftRuleConfig ruleConfig = gameLuckyGiftConfigConvertor.toGameLuckyGiftRuleConfig(
        param);
    if (Objects.nonNull(param.getId())) {
      ResponseAssert.isTrue(CommonErrorCode.UPDATE_FAILURE,
          gameLuckyGiftRuleConfigService.updateSelectiveById(ruleConfig));
      gameLuckyGiftCacheService.removeBaseConfig();
      return;
    }

    gameLuckyGiftRuleConfigService.save(ruleConfig);
  }

  @Override
  public PageResult<GameLuckyGiftStandardConfigDTO> getStandardConfig(
      GameLuckGiftStandardConfigQryCmd query) {
    PageResult<GameLuckyGiftStandardConfig> pageResult = gameLuckyGiftStandardConfigService.getStandardConfig(
        query);
    return pageResult.convert(gameLuckyGiftConfigConvertor::toGameLuckyGiftStandardConfigDTO);
  }

  @Override
  public void addLuckyGiftStandardConfig(GameLuckyGiftStandardConfigDTO param) {
    GameLuckyGiftStandardConfig standardConfig = gameLuckyGiftConfigConvertor.toGameLuckyGiftStandardConfig(
        param);
    if (Objects.nonNull(param.getId())) {
      gameLuckyGiftStandardConfigService.updateSelectiveById(standardConfig);
      return;
    }
    gameLuckyGiftStandardConfigService.save(standardConfig);
  }

  @Override
  public void deleteStandardConfig(Long id, Long userId) {

    // 是否关联礼物
    List<GiftConfig> sysGiftConfigs = giftConfigService.getLuckyGiftByStandardId(id,
        GiftTabEnum.LUCKY_GIFT.name());
    ResponseAssert.isTrue(GiftErrorCode.GAME_LUCKY_GIFT_STANDARD_DELETED_ERROR,
        CollectionUtils.isEmpty(sysGiftConfigs));

    //删除基础配置和详情
    ResponseAssert.isTrue(CommonErrorCode.DELETE_FAILURE, deleteProbabilityInfo(id));

    //清除缓存
    gameLuckyGiftCacheService.removeInventoryTemplate(id);

    gameLuckyGiftStandardConfigService.deleteStandardConfig(id, userId);

  }

  private Boolean deleteProbabilityInfo(Long id) {
    List<LuckyGiftProbability> gameLuckyGiftProbabilities = luckyGiftProbabilityService.getLuckyGiftProbabilityByStandardId(
        id);
    if (CollectionUtils.isEmpty(gameLuckyGiftProbabilities)) {
      return true;
    }

    Set<Long> probabilityIds = gameLuckyGiftProbabilities.stream()
        .map(LuckyGiftProbability::getId).collect(
            Collectors.toSet());

    luckyGiftProbabilityDetailsService.deleteByProbabilityIds(probabilityIds);

    ResponseAssert.isTrue(CommonErrorCode.DELETE_FAILURE,
        luckyGiftProbabilityService.deleteByStandardId(id));
    return true;
  }

  @Override
  public List<GameLuckyGiftProbabilityDTO> getLuckyGiftProbabilityConfig(
      GameLuckGiftProbabilityConfigQryCmd query) {
    Map<Long, List<LuckyGiftProbabilityDetails>> probabilityDetailsMap = luckyGiftProbabilityDetailsService.getLuckyGiftProbabilityDetails(
        query.getSysOrigin());

    List<LuckyGiftProbability> probabilityList = luckyGiftProbabilityService.getLuckyGiftProbabilityConfig(
        query);

    if (CollectionUtils.isEmpty(probabilityList)) {
      return Lists.newArrayList();
    }

    return probabilityList.stream().map(luckyGiftProbability -> {
      GameLuckyGiftProbabilityDTO gameLuckyGiftProbabilityVO = gameLuckyGiftConfigConvertor.toGameLuckyGiftProbabilityDTO(
          luckyGiftProbability);
      gameLuckyGiftProbabilityVO.setGameLuckyGiftProbabilityDetails(
          gameLuckyGiftConfigConvertor.toListLuckyGiftProbabilityDetailsDTO(
              probabilityDetailsMap.get(gameLuckyGiftProbabilityVO.getId())));
      return gameLuckyGiftProbabilityVO;

    }).collect(Collectors.toList());
  }

  @Override
  public void addLuckyGiftProbabilityInfoConfig(GameLuckyGiftProbabilityInfoDTO param) {
    GameLuckyGiftProbabilityDTO luckyGiftProbability = addLuckyGiftProbabilityConfig(param);
    luckyGiftProbabilityDetailsService.add(luckyGiftProbability.getId(),
        getGameLuckyGiftProbabilityDetails(param,
            luckyGiftProbability));

  }

  private GameLuckyGiftProbabilityDTO addLuckyGiftProbabilityConfig(
      GameLuckyGiftProbabilityInfoDTO param) {
    GameLuckyGiftProbabilityDTO gameLuckyGiftProbability = param.getGameLuckyGiftProbability();
    if (Objects.nonNull(gameLuckyGiftProbability.getId())) {

      // 校验数据是否发生变动
      ResponseAssert.isFalse(GiftErrorCode.GAME_LUCKY_GIFT_PROBABILITY_CONFIG_UPDATE_ERROR,
          checkDateChange(param));

      ResponseAssert.isTrue(CommonErrorCode.UPDATE_FAILURE,
          luckyGiftProbabilityService.updateSelectiveById(
              gameLuckyGiftConfigConvertor.toGameLuckyGiftProbability(gameLuckyGiftProbability)));

      List<GiftConfig> sysGiftConfigs = giftConfigService.getLuckyGiftByStandardId(
          gameLuckyGiftProbability.getStandardId(), GiftTabEnum.LUCKY_GIFT.name());

      if (CollectionUtils.isNotEmpty(sysGiftConfigs)) {
        // 清理礼物实际库存
        gameLuckyGiftCacheService.removeRemainingInventory(sysGiftConfigs.stream()
                .map(GiftConfig::getId).collect(Collectors.toSet()),
            gameLuckyGiftProbability.getGiftQuantity(),
            gameLuckyGiftProbability.getStandardId());
      }
      return gameLuckyGiftProbability;
    }
    LuckyGiftProbability giftProbability = gameLuckyGiftConfigConvertor.toGameLuckyGiftProbability(
        gameLuckyGiftProbability);
    luckyGiftProbabilityService.save(giftProbability);
    gameLuckyGiftProbability.setId(giftProbability.getId());
    return gameLuckyGiftProbability;
  }

  private List<LuckyGiftProbabilityDetails> getGameLuckyGiftProbabilityDetails(
      GameLuckyGiftProbabilityInfoDTO param, GameLuckyGiftProbabilityDTO luckyGiftProbability) {
    return param.getGameLuckyGiftProbabilityDetails().stream()
        .map(gameLuckyGiftProbabilityDetailsDto -> {
          LuckyGiftProbabilityDetails giftProbabilityDetails = gameLuckyGiftConfigConvertor.toLuckyGiftProbabilityDetails(
              gameLuckyGiftProbabilityDetailsDto);
          Integer quantity = new BigDecimal(
              luckyGiftProbability.getSignTotal().toString()).divide(new BigDecimal("10000"))
              .multiply(new BigDecimal(giftProbabilityDetails.getProbability().toString()))
              .intValue();
          giftProbabilityDetails.setQuantity(quantity);
          giftProbabilityDetails.setSysOrigin(luckyGiftProbability.getSysOrigin());
          giftProbabilityDetails.setProbabilityId(luckyGiftProbability.getId());
          giftProbabilityDetails.setDel(Boolean.FALSE);
          giftProbabilityDetails.setCreateTime(TimestampUtils.now());
          giftProbabilityDetails.setUpdateTime(TimestampUtils.now());
          giftProbabilityDetails.setCreateUser(luckyGiftProbability.getCreateUser());
          return giftProbabilityDetails;
        }).collect(Collectors.toList());
  }

  private Boolean checkDateChange(GameLuckyGiftProbabilityInfoDTO param) {
    Boolean probabilityFlag = false;
    GameLuckyGiftProbabilityDTO gameLuckyGiftProbabilityDto = param.getGameLuckyGiftProbability();
    LuckyGiftProbability gameLuckyGiftProbability = luckyGiftProbabilityService.getById(
        gameLuckyGiftProbabilityDto.getId());
    if (Objects.isNull(gameLuckyGiftProbability)) {
      return true;
    }

    if (Objects.equals(gameLuckyGiftProbabilityDto.getGiftQuantity(),
        gameLuckyGiftProbability.getGiftQuantity()) &&
        Objects.equals(gameLuckyGiftProbabilityDto.getGiftGiveTotal(),
            gameLuckyGiftProbability.getGiftGiveTotal()) &&
        Objects.equals(gameLuckyGiftProbabilityDto.getComboIncrements(),
            gameLuckyGiftProbability.getComboIncrements()) &&
        Objects.equals(gameLuckyGiftProbabilityDto.getSignTotal(),
            gameLuckyGiftProbability.getSignTotal())
    ) {
      probabilityFlag = true;
    }
    List<GameLuckyGiftProbabilityDetailsDTO> gameLuckyGiftProbabilityDetailsDto = param.getGameLuckyGiftProbabilityDetails();
    List<LuckyGiftProbabilityDetails> probabilityDetailsList = luckyGiftProbabilityDetailsService.getDetailByProbabilityId(
        gameLuckyGiftProbabilityDto.getId());
    if (CollectionUtils.isEmpty(gameLuckyGiftProbabilityDetailsDto) || CollectionUtils.isEmpty(
        probabilityDetailsList)) {
      return true;
    }
    if (gameLuckyGiftProbabilityDetailsDto.size() == probabilityDetailsList.size()
        && probabilityFlag) {

      Map<Long, LuckyGiftProbabilityDetails> probabilityMap = new HashMap<>();

      for (LuckyGiftProbabilityDetails details : probabilityDetailsList) {
        probabilityMap.put(details.getId(), details);
      }

      for (GameLuckyGiftProbabilityDetailsDTO dto : gameLuckyGiftProbabilityDetailsDto) {
        LuckyGiftProbabilityDetails details = probabilityMap.get(dto.getId());

        if (details == null || !details.getProbability().equals(dto.getProbability()) ||
            !details.getMultiple().equals(dto.getMultiple())) {
          return false;
        }
      }
    } else {
      probabilityFlag = false;
    }
    return probabilityFlag;
  }
}
