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

import com.red.circle.auth.inner.endpoint.AuthClient;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
import com.red.circle.external.inner.model.cmd.message.BroadcastGroupMsgBodyCmd;
import com.red.circle.external.inner.model.enums.message.GroupMessageTypeEnum;
import com.red.circle.framework.core.dto.ReqSysOrigin;
import com.red.circle.framework.core.security.UserCredential;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.order.inner.model.enums.MonthlyRechargeType;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.cmd.activity.RankingDataUpdateCmd;
import com.red.circle.other.app.dto.cmd.party3rd.*;
import com.red.circle.other.app.dto.cmd.task.RoomDailyTaskProgressUpdateCmd;
import com.red.circle.other.app.enums.violation.GameOriginEnum;
import com.red.circle.other.app.service.activity.ActivityRechargeTicketService;
import com.red.circle.other.app.service.activity.RankingActivityService;
import com.red.circle.other.app.service.game.override.service.YomiGameService;
import com.red.circle.other.app.service.task.RoomDailyTaskProgressService;
import com.red.circle.other.app.util.DateTimeAsiaRiyadhUtils;
import com.red.circle.other.app.util.OfficialNoticeUtils;
import com.red.circle.other.domain.game.GameRankingIncrementCmd;
import com.red.circle.other.domain.gateway.game.GameRankingGateway;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.domain.ranking.RankingActivityType;
import com.red.circle.other.domain.ranking.RankingCycleType;
import com.red.circle.other.domain.ranking.RankingDimension;
import com.red.circle.other.infra.config.YomiConfig;
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
import com.red.circle.other.infra.database.rds.entity.sys.GameListConfig;
import com.red.circle.other.infra.database.rds.service.sys.GameListConfigService;
import com.red.circle.other.inner.enums.config.EnumConfigKey;
import com.red.circle.other.inner.enums.task.RoomDailyTaskCode;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.tool.core.num.ArithmeticUtils;
import com.red.circle.tool.core.tuple.PennyAmount;
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.dto.WalletReceiptResDTO;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * Yomi游戏服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class YomiGameServiceImpl implements YomiGameService {
    
    private final YomiConfig yomiConfig;
    private final RedisTemplate<String, String> redisTemplate;
    private final AuthClient authClient;
    private final UserProfileGateway userProfileGateway;
    private final WalletGoldClient walletGoldClient;
    private final GameListConfigService gameListConfigService;
    private final EnumConfigCacheService enumConfigCacheService;
    private final ImGroupClient imGroupClient;
    private final UserProfileAppConvertor userProfileAppConvertor;
    private final RankingActivityService rankingActivityService;
    private final GameActivityService gameActivityService;
    private final GameRankingGateway gameRankingGateway;
    private final ActivityRechargeTicketService activityRechargeTicketService;
    private final RoomDailyTaskProgressService roomDailyTaskProgressService;
    private final RedisService redisService;
    
    @Override
    public YomiTokenCO getToken(YomiGetTokenCmd cmd) {
        log.info("yomi获取token: userId={}, gameId={}", cmd.getUserId(), cmd.getGameId());
        
        try {
            // 调用认证服务获取用户凭证
            ResultResponse<UserCredential> response = authClient.getUserCredential(Long.parseLong(cmd.getUserId()));
            UserCredential credential = response.getBody();
            
            if (credential == null) {
                throw new RuntimeException("用户不存在");
            }
            
            // 生成系统标准token
            String token = credential.token();
            
            // 过期时间(24小时后)
            Long expireDate = System.currentTimeMillis() / 1000 + yomiConfig.getTokenExpireSeconds();
            
            // 缓存token-userId映射
            String cacheKey = buildTokenCacheKey(token);
            redisTemplate.opsForValue().set(cacheKey, cmd.getUserId(), 
                yomiConfig.getTokenExpireSeconds(), TimeUnit.SECONDS);

            return new YomiTokenCO(token, expireDate);
            
        } catch (Exception e) {
            log.error("yomi获取token失败: userId={}, error={}", cmd.getUserId(), e.getMessage(), e);
            throw new RuntimeException("获取token失败: " + e.getMessage());
        }
    }
    
    @Override
    public YomiUserInfoCO getUserInfo(YomiUserInfoCmd cmd) {
        String userId = cmd.getUserId();
        log.info("yomi获取用户信息: userId={}, gameId={}", userId, cmd.getGameId());
        
        try {
            // 验证token
            if (!UserCredential.checkToken(cmd.getToken(), Long.parseLong(userId))) {
                throw new Exception("token与用户ID不匹配");
            }
            
            // 获取用户信息
            UserProfile profile = userProfileGateway.getByUserId(Long.parseLong(userId));

            if (profile == null) {
                throw new Exception("用户信息不存在");
            }
            
            // 获取用户余额
            ResultResponse<PennyAmount> response = walletGoldClient.getBalance(Long.parseLong(userId));

            YomiUserInfoCO result = new YomiUserInfoCO(
                userId,
                profile.getUserNickname(),
                profile.getUserAvatar(),
                    response.getBody().getDollarAmount().intValue()
            );
            return result;
            
        } catch (Exception e) {
            log.error("yomi获取用户信息失败: userId={}, error={}", userId, e.getMessage(), e);
            throw new RuntimeException(e.getMessage());
        }
    }
    
    @Override
    public YomiBalanceCO changeBalance(YomiChangeBalanceCmd cmd) {
        Long userId = Long.parseLong(cmd.getUserId());
        Integer changeValue = cmd.getChangeValue();
        log.info("yomi余额变动: userId={}, gameId={}, changeValue={}, changeCause={}, recordId={}",
                userId, cmd.getGameId(), changeValue, cmd.getChangeCause(), cmd.getRecordId());
        
        try {
            // 验证token
            String token = cmd.getToken();
            String gameId = cmd.getGameId();

            if (!UserCredential.checkToken(token, userId)) {
                throw new Exception("token与用户ID不匹配");
            }

            WalletReceiptResDTO res = walletGoldClient.changeBalance(createReceipt(cmd)).getBody();
            int currentBalance = res.getBalance().getDollarAmount().intValue();

            // 获取游戏配置
            String sysOrigin = UserCredential.parseToken(token).getSysOrigin();
            GameListConfig gameConfig = gameListConfigService.getByGameId(gameId, GameOriginEnum.YOMI.name(), sysOrigin);
            if (gameConfig == null) {
                log.error("游戏配置不存在, gameId={}", gameId);
                return new YomiBalanceCO(currentBalance);
            }

            // 发送广播通知
            if (!isConsume(cmd)) {
                sendBroadcast(userId, changeValue, gameConfig.getCover());

                // 累计游戏排行榜
                incGameRankingRecord(changeValue, gameConfig);

                // 游戏参与打榜活动
                incGameRankingActivity(userId, changeValue, gameConfig.getGameId());

                //处理游戏获得任务
                gameActivityService.handleGameSpendTask(userId, changeValue.longValue());

                // 累加用户获得的金币并发送抽奖券
//                activityRechargeTicketService.accumulatedRechargeAndAddTicket(userId, Math.abs(changeValue.longValue()), MonthlyRechargeType.UNDEFINED);
            } else {
                updateRoomDailyTask(changeValue.longValue(), userId);
            }

            return new YomiBalanceCO(currentBalance);
            
        } catch (Exception e) {
            log.error("yomi余额变动失败: userId={}, recordId={}, error={}",
                    userId, cmd.getRecordId(), e.getMessage(), e);
            throw new RuntimeException("余额变动失败: " + e.getMessage());
        }
    }

    private void updateRoomDailyTask(Long coins, Long userId) {
        RoomDailyTaskCode taskType = RoomDailyTaskCode.PERSONAL_GAME_CONSUME;
        String redisKey = "room:daily:task:progress:" + taskType.name() + ":" + userId + ":" + ZonedDateTimeAsiaRiyadhUtils.now().toLocalDate();
        Long total = redisService.increment(redisKey, Math.abs(coins.intValue()));
        redisService.expire(redisKey, DateTimeAsiaRiyadhUtils.getSecondsUntilMidnight(), TimeUnit.SECONDS);
        roomDailyTaskProgressService.updateTaskProgress(
                new RoomDailyTaskProgressUpdateCmd()
                        .setUserId(userId)
                        .setTaskCode(taskType.name())
                        .setProgressValue(total.intValue())
        );
    }

    private static boolean isConsume(YomiChangeBalanceCmd cmd) {
        return "bet".equals(cmd.getChangeCause());
    }

    /**
     * 验证token有效性
     */
    private String validateToken(String token) {
        String cacheKey = buildTokenCacheKey(token);
        String userId = redisTemplate.opsForValue().get(cacheKey);
        
        if (userId == null) {
            throw new RuntimeException("token已过期或无效");
        }
        
        return userId;
    }
    
    /**
     * 构建token缓存key
     */
    private String buildTokenCacheKey(String token) {
        return "yomi:token:" + token;
    }


    private GoldReceiptCmd createReceipt(YomiChangeBalanceCmd cmd) {
        UserCredential userCredential = UserCredential.parseToken(cmd.getToken());
        return createGoldReceiptCmdBuilder(cmd.getChangeCause())
                .userId(Long.parseLong(cmd.getUserId()))
                .sysOrigin(userCredential.getSysOrigin())
                .origin(GoldOrigin.YOMI_GAME.name() + "_" + cmd.getGameId())
                .originDescribe(GoldOrigin.YOMI_GAME.getDesc() + "[" + cmd.getGameId() + "]")
                .eventId(cmd.getRoundId())
                .amount(ArithmeticUtils.toBigDecimal(Math.abs(cmd.getChangeValue())))
                .build();
    }


    private GoldReceiptCmd.GoldReceiptCmdBuilder createGoldReceiptCmdBuilder(String changeCause) {
        if ("bet".equals(changeCause)) {
            return GoldReceiptCmd.builder().appExpenditure();
        }

        if ("awards".equals(changeCause)) {
            return GoldReceiptCmd.builder().appIncome();
        }

        throw new IllegalArgumentException("yomi game param [changeCause] error: " + changeCause);
    }


    /**
     * 构建游戏参数(用于广播和排行榜)
     */
    private Map<String, Object> buildGameParam(YomiChangeBalanceCmd cmd, Long userId, GameListConfig gameConfig) {
        Map<String, Object> param = new HashMap<>();
        param.put("userId", userId);
        param.put("gameId", cmd.getGameId());
        param.put("roomId", cmd.getRoomId());
        param.put("recordId", cmd.getRecordId());
        param.put("roundId", cmd.getRoundId());
        param.put("changeValue", cmd.getChangeValue());
        param.put("changeCause", cmd.getChangeCause());
        param.put("changeTime", cmd.getChangeTime());
        param.put("gameConfig", gameConfig);
        return param;
    }

    private void sendBroadcast(Long userId, Integer rewardAmount, String gameUrl) {
        if (rewardAmount == null ||  rewardAmount <= 0) {
            return;
        }

        BigDecimal cost = enumConfigCacheService.getValueBigDecimal(EnumConfigKey.GAME_BROADCAST_AMOUNT, SysOriginPlatformEnum.LIKEI.name()) ;
        int thresholdAmount = Optional.ofNullable(cost).orElse(new BigDecimal("5000")).intValue();
        if (rewardAmount < thresholdAmount) {
            return;
        }

        UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO(userProfileGateway.getByUserId(userId));

        Map<Object, Object> build = OfficialNoticeUtils.buildUserProfile(userProfile);
        build.put("gameUrl", gameUrl);
        build.put("currencyDiff", rewardAmount);

        imGroupClient.sendMessageBroadcast(
                BroadcastGroupMsgBodyCmd.builder()
                        .toPlatform(SysOriginPlatformEnum.LIKEI)
                        .type(GroupMessageTypeEnum.GAME_BAISHUN_WIN)
                        .data(build)
                        .build()
        );
    }

    private void incGameRankingRecord(Integer rewardAmount, GameListConfig gameListConfig) {

        GameRankingIncrementCmd build = GameRankingIncrementCmd.builder()
                .gameOrigin(GameOriginEnum.YOMI.name())
                .gameId(gameListConfig.getGameId())
                .gameName(gameListConfig.getName())
                .gameCover(gameListConfig.getCover())
                .gameUrl(gameListConfig.getGameCode())
                .sysOrigin(gameListConfig.getSysOrigin())
                .amount(rewardAmount.longValue())
                .periodType("ALL")
                .build();
        gameRankingGateway.incrementPrizeAmount(build);
    }


    private void incGameRankingActivity(Long userId, Integer rewardAmount, String gameId) {
        RankingDataUpdateCmd receiverCmd = new RankingDataUpdateCmd();
        receiverCmd.setUserId(userId);
        receiverCmd.setUserSex(1);
        receiverCmd.setActivityType(RankingActivityType.KING_GAMES.getCode());
        receiverCmd.setCycleType(RankingCycleType.WEEKLY.getCode());
        receiverCmd.setCycleKey(ZonedDateTimeAsiaRiyadhUtils.nowWeekMondayToInt().toString());
        receiverCmd.setDimension(RankingDimension.GAME_WIN.getCode());
        receiverCmd.setIncrementQuantity(rewardAmount.longValue());
        receiverCmd.setBizNo(gameId);
        receiverCmd.setReqSysOrigin(ReqSysOrigin.of("LIKEI"));
        rankingActivityService.accumulateRankingData(receiverCmd);

        //游戏王日榜
        gameActivityService.incKingGameDaily(userId, rewardAmount.longValue(), gameId);
    }
}