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

import com.red.circle.auth.inner.endpoint.AuthClient;
import com.red.circle.component.game.baishun.GameBaishunService;
import com.red.circle.component.game.baishun.error.BaishunErrorCode;
import com.red.circle.component.game.baishun.props.GameBaishunProperties;
import com.red.circle.component.game.baishun.request.BaishunChangeCurrencyRequest;
import com.red.circle.component.game.baishun.request.BaishunTokenRequest;
import com.red.circle.component.game.baishun.request.BaishunTokenUpdateRequest;
import com.red.circle.component.game.baishun.request.BaishunUserProfileRequest;
import com.red.circle.component.game.baishun.response.BaishunChangeCurrencyResponse;
import com.red.circle.component.game.baishun.response.BaishunResponse;
import com.red.circle.component.game.baishun.response.BaishunTokenResponse;
import com.red.circle.component.game.baishun.response.BaishunUserProfileResponse;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.exception.ResponseException;
import com.red.circle.framework.core.security.UserCredential;
import com.red.circle.mq.business.model.event.game.GameBaiShunTwoFunProperties;
import com.red.circle.mq.business.model.event.task.TaskApprovalEvent;
import com.red.circle.mq.rocket.business.producer.TaskMqMessage;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.date.DateUtils;
import com.red.circle.tool.core.date.LocalDateTimeUtils;
import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.tool.core.parse.DataTypeUtils;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd.GoldReceiptCmdBuilder;
import com.red.circle.wallet.inner.model.dto.WalletReceiptResDTO;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import java.math.BigDecimal;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * baishun游戏服务 实现.
 *
 * @author pengliang on 2023/9/13
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GameBaishunServiceImpl implements GameBaishunService {

  private final AuthClient authClient;
  private final RedisService redisService;
  private final WalletGoldClient walletGoldClient;
  private final UserProfileGateway userProfileGateway;
  private final GameBaishunProperties gameBaishunProperties;
  private final TaskMqMessage taskMqMessage;
  private final GameBaiShunTwoFunProperties gameBaiShunTwoFunProperties;
  private final UserProfileAppConvertor userProfileAppConvertor;

  @Override
  public BaishunResponse<BaishunTokenResponse> getToken(BaishunTokenRequest request) {
    log.info("getToken: {}", request);
    if (!request.checkSignature(gameBaishunProperties.getAppKey())) {
      log.info("getToken: {}", "验证签名失败");
      return BaishunResponse.fail(BaishunErrorCode.SIGNATURE_ERROR);
      /*if(!request.checkSignature(gameBaiShunTwoFunProperties.getAppKey())) {
        return BaishunResponse.fail(BaishunErrorCode.SIGNATURE_ERROR);
      }*/
    }

    return getToken(request.getUserId());
  }

  @Override
  public BaishunResponse<BaishunUserProfileResponse> getUserProfile(BaishunUserProfileRequest request) {
    log.info("getUserProfile: {}", request);
    if (!request.checkSignature(gameBaishunProperties.getAppKey())) {
      /*if(!request.checkSignature(gameBaiShunTwoFunProperties.getAppKey())) {
        return BaishunResponse.fail(BaishunErrorCode.SIGNATURE_ERROR);
      }*/
      log.info("getToken: {}", "验证签名失败");
      return BaishunResponse.fail(BaishunErrorCode.SIGNATURE_ERROR);
    }

    if (!checkTokenStrict(request)) {
      return BaishunResponse.fail(BaishunErrorCode.USER_ACCOUNT_LIMIT);
    }

    UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO(
        userProfileGateway.getByUserId(DataTypeUtils.toLong(request.getUserId())));
    if (Objects.isNull(userProfile)) {
      return BaishunResponse.fail(BaishunErrorCode.READ_DATE_ERROR);
    }

    return BaishunResponse.success(new BaishunUserProfileResponse()
        .setUserId(request.getUserId())
        .setUserName(userProfile.getUserNickname())
        .setUserAvatar(userProfile.getUserAvatar())
        .setBalance(ResponseAssert.requiredSuccess(walletGoldClient.getBalance(userProfile.getId()))
            .getDollarAmount())
    );
  }

  @Override
  public BaishunResponse<BaishunTokenResponse> updateToken(BaishunTokenUpdateRequest request) {
    log.info("updateToken: {}", request);
    if (!request.checkSignature(gameBaishunProperties.getAppKey())) {
      log.info("getToken: {}", "验证签名失败");
      return BaishunResponse.fail(BaishunErrorCode.SIGNATURE_ERROR);
      /*if(!request.checkSignature(gameBaiShunTwoFunProperties.getAppKey())) {
        return BaishunResponse.fail(BaishunErrorCode.SIGNATURE_ERROR);
      }*/
    }

    if (!UserCredential.checkToken(request.getToken(), DataTypeUtils.toLong(request.getUserId()))) {
      return BaishunResponse.fail(BaishunErrorCode.USER_ACCOUNT_LIMIT);
    }

    return getToken(request.getUserId());
  }

  @Override
  public BaishunResponse<BaishunChangeCurrencyResponse> changeBalance(BaishunChangeCurrencyRequest request) {
    log.info("changeBalance: {}", request);
    if (!request.checkSignature(gameBaishunProperties.getAppKey())) {
      log.info("getToken: {}", "验证签名失败");
      return BaishunResponse.fail(BaishunErrorCode.SIGNATURE_ERROR);
      /*if(!request.checkSignature(gameBaiShunTwoFunProperties.getAppKey())) {
        return BaishunResponse.fail(BaishunErrorCode.SIGNATURE_ERROR);
      }*/
    }

    if (!UserCredential.checkToken(request.getToken(), DataTypeUtils.toLong(request.getUserId()))) {
      return BaishunResponse.fail(BaishunErrorCode.USER_ACCOUNT_LIMIT);
    }

    if (Objects.equals(request.getCurrencyDiff(), 0L)) {
      return BaishunResponse.fail(BaishunErrorCode.DATE_ERROR);
    }

    if (!redisService.setIfAbsent("GBAISHUN:" + request.getOrderId(), 5,
        TimeUnit.MINUTES)) {
      log.warn("重复触发消息: {}", JacksonUtils.toJson(request));
      return null;
    }

    try {
      WalletReceiptResDTO receiptRes = walletGoldClient.changeBalance(createReceipt(request))
          .getBody();

      //游玩一句游戏结束 每日任务  baishun
      Long userId = DataTypeUtils.toLong(request.getUserId());
      taskMqMessage.sendTask(TaskApprovalEvent.builder()
              .taskId(4)
              .userId(userId)
              .day(LocalDateTimeUtils.nowFormat("yyyy-MM-dd"))
              .currencyDiff(request.getCurrencyDiff())
              .sysOrigin(UserCredential.parseToken(request.getToken()).getSysOrigin())
              .gameName(GoldOrigin.BAISHUN_GAME.name())
              .gameId(Long.parseLong(request.getGameId()))
              .build());
      log.warn("{} 发送游戏获奖通知--金币数量{}", GoldOrigin.BAISHUN_GAME.name(), request.getCurrencyDiff());
      return BaishunResponse.success(new BaishunChangeCurrencyResponse()
              .setCurrencyBalance(receiptRes.getBalance().getDollarAmount().stripTrailingZeros()),
          Objects.toString(receiptRes.getAssetRecordId()));
    } catch (ResponseException ex) {
      if (Objects.equals(ex.getErrorCode(), 5000)) {
        return BaishunResponse.fail(BaishunErrorCode.INSUFFICIENT_ASSETS);
      }
    } catch (Exception ex) {
      return BaishunResponse.fail(BaishunErrorCode.SERVER_ERROR, ex.getMessage());
    }




    return BaishunResponse.fail(BaishunErrorCode.SERVER_ERROR);
  }

  private GoldReceiptCmd createReceipt(BaishunChangeCurrencyRequest param) {
    UserCredential userCredential = UserCredential.parseToken(param.getToken());
    return createGoldReceiptCmdBuilder(param.getCurrencyDiff())
        .userId(DataTypeUtils.toLong(param.getUserId()))
        .sysOrigin(userCredential.getSysOrigin())
        .origin(GoldOrigin.BAISHUN_GAME.name() + "_" + param.getGameId())
        .originDescribe(GoldOrigin.BAISHUN_GAME.getDesc() + "[" + param.getGameId() + "]")
        .eventId(param.getOrderId())
        .amount(toPositiveBigDecimal(param.getCurrencyDiff()))
        .build();
  }

  private GoldReceiptCmdBuilder createGoldReceiptCmdBuilder(Long currencyDiff) {
    return currencyDiff > 0
        ? GoldReceiptCmd.builder().appIncome()
        : GoldReceiptCmd.builder().appExpenditure();
  }

  private BigDecimal toPositiveBigDecimal(Long currencyDiff) {
    return new BigDecimal(currencyDiff.toString().replace("-", ""));
  }

  private BaishunResponse<BaishunTokenResponse> getToken(String userId) {
    UserCredential accessToken = ResponseAssert.requiredSuccess(
        authClient.getUserCredential(DataTypeUtils.toLong(userId))
    );

    if (Objects.isNull(accessToken)) {
      return BaishunResponse.fail(BaishunErrorCode.READ_DATE_ERROR);
    }

    return BaishunResponse.success(new BaishunTokenResponse()
        .setToken(accessToken.token())
        .setExpireDate(Objects.nonNull(accessToken.getExpireTime())
            ? accessToken.getExpireTime()
            : DateUtils.nowMinusHours(2).getTime()));
  }

  private boolean checkTokenStrict(BaishunUserProfileRequest request) {
    UserCredential accessToken = ResponseAssert.requiredSuccess(
        authClient.getUserCredential(DataTypeUtils.toLong(request.getUserId())));

    if (Objects.isNull(accessToken)) {
      return false;
    }

    if (!Objects.equals(accessToken.getUserId(), DataTypeUtils.toLong(request.getUserId()))) {
      return false;
    }

    return Objects.equals(accessToken.token(), request.getToken());
  }

}
