package com.zanxiang.game.back.serve.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.sd4324530.jtuple.Tuple2;
import com.zanxiang.advertising.tencent.base.AdvertisingTencentServer;
import com.zanxiang.advertising.tencent.base.rpc.IUserActionSetRpc;
import com.zanxiang.game.back.serve.dao.mapper.GameTencentMiniGameRoleRegisterMapper;
import com.zanxiang.game.back.serve.pojo.TutorialFinish;
import com.zanxiang.game.back.serve.pojo.dto.GameTencentMiniGameRoleRegisterDTO;
import com.zanxiang.game.back.serve.pojo.entity.GameBackPolicy;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameBackLog;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameRoleRegister;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameUser;
import com.zanxiang.game.back.serve.pojo.enums.ActionTypeEnum;
import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
import com.zanxiang.game.back.serve.pojo.enums.BackTypeEnum;
import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniGameRoleRegisterVO;
import com.zanxiang.game.back.serve.service.IGameBackPolicyService;
import com.zanxiang.game.back.serve.service.IGameTencentMiniGameBackLogService;
import com.zanxiang.game.back.serve.service.IGameTencentMiniGameRoleRegisterService;
import com.zanxiang.game.back.serve.service.IGameTencentMiniGameUserService;
import com.zanxiang.game.module.base.ServerInfo;
import com.zanxiang.game.module.base.pojo.vo.AgentRpcVO;
import com.zanxiang.game.module.base.rpc.IAgentRpc;
import com.zanxiang.module.util.JsonUtil;
import com.zanxiang.module.util.bean.BeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class GameTencentMiniGameRoleRegisterServiceImpl extends ServiceImpl<GameTencentMiniGameRoleRegisterMapper, GameTencentMiniGameRoleRegister>
        implements IGameTencentMiniGameRoleRegisterService {

    @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)
    private IAgentRpc agentRpc;

    @DubboReference(providedBy = AdvertisingTencentServer.SERVER_DUBBO_NAME)
    private IUserActionSetRpc userActionSetRpc;

    @Autowired
    private IGameTencentMiniGameBackLogService gameTencentMiniGameBackLogService;

    @Autowired
    private IGameTencentMiniGameUserService gameTencentMiniGameUserService;

    @Autowired
    private IGameBackPolicyService gameBackPolicyService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean roleRegisterBack(GameTencentMiniGameRoleRegister roleRegisterLog) {
        if (StringUtils.isBlank(roleRegisterLog.getClickId())) {
            return false;
        }
        Tuple2<BackStatusEnum, String> backResult = doCallback(roleRegisterLog);
        return update(new LambdaUpdateWrapper<GameTencentMiniGameRoleRegister>()
                .set(GameTencentMiniGameRoleRegister::getBackStatus, backResult.first.getBackStatus())
                .eq(GameTencentMiniGameRoleRegister::getId, roleRegisterLog.getId())
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean callback(GameTencentMiniGameRoleRegister roleRegisterLog) {
        BackStatusEnum backStatusEnum = this.doCallbackMediaSdk(roleRegisterLog);
        return update(new LambdaUpdateWrapper<GameTencentMiniGameRoleRegister>()
                .set(GameTencentMiniGameRoleRegister::getBackStatus, backStatusEnum.getBackStatus())
                .eq(GameTencentMiniGameRoleRegister::getId, roleRegisterLog.getId())
        );
    }

    @Override
    public IPage<GameTencentMiniGameRoleRegisterVO> listOfPage(GameTencentMiniGameRoleRegisterDTO dto) {
        IPage<GameTencentMiniGameRoleRegister> page = page(dto.toPage(), new LambdaQueryWrapper<GameTencentMiniGameRoleRegister>()
                .eq(StringUtils.isNotBlank(dto.getAgentKey()), GameTencentMiniGameRoleRegister::getAgentKey, dto.getAgentKey())
                .ge(dto.getRegisterTimeBegin() != null, GameTencentMiniGameRoleRegister::getRegisterTime, dto.getRegisterTimeBegin() == null ? null : LocalDateTime.of(dto.getRegisterTimeBegin(), LocalTime.MIDNIGHT))
                .le(dto.getRegisterTimeEnd() != null, GameTencentMiniGameRoleRegister::getRegisterTime, dto.getRegisterTimeEnd() == null ? null : LocalDateTime.of(dto.getRegisterTimeEnd(), LocalTime.MAX))
                .eq(null != dto.getGameId(), GameTencentMiniGameRoleRegister::getGameId, dto.getGameId())
                .eq(null != dto.getAdAccountId(), GameTencentMiniGameRoleRegister::getAdAccountId, dto.getAdAccountId())
                .eq(StringUtils.isNotBlank(dto.getWechatAppId()), GameTencentMiniGameRoleRegister::getWechatAppId, dto.getWechatAppId())
                .eq(StringUtils.isNotBlank(dto.getWechatOpenid()), GameTencentMiniGameRoleRegister::getWechatOpenid, dto.getWechatOpenid())
                .eq(null != dto.getBackStatus(), GameTencentMiniGameRoleRegister::getBackStatus, dto.getBackStatus())
                .orderByDesc(GameTencentMiniGameRoleRegister::getCreateTime)
        );
        IPage<GameTencentMiniGameRoleRegisterVO> result = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return result;
        }
        result.setRecords(toVOBatch(page.getRecords()));
        return result;
    }

    @Override
    public boolean doReport(List<Long> userLogIds) {
        listByIds(userLogIds).forEach(userLog -> {
            Tuple2<BackStatusEnum, String> backResult = doCallback(userLog);
            update(new LambdaUpdateWrapper<GameTencentMiniGameRoleRegister>()
                    .set(GameTencentMiniGameRoleRegister::getBackStatus, backResult.first.getBackStatus())
                    .eq(GameTencentMiniGameRoleRegister::getId, userLog.getId())
            );
        });
        return true;
    }

    private List<GameTencentMiniGameRoleRegisterVO> toVOBatch(List<GameTencentMiniGameRoleRegister> logList) {
        if (CollectionUtils.isEmpty(logList)) {
            return Collections.emptyList();
        }
        Set<String> agentKeys = logList.stream().map(GameTencentMiniGameRoleRegister::getAgentKey).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
        Map<String, AgentRpcVO> agentMap = CollectionUtils.isEmpty(agentKeys) ? Collections.emptyMap() : agentRpc.getByAgentKeys(new ArrayList<>(agentKeys))
                .getData().stream().collect(Collectors.toMap(AgentRpcVO::getAgentKey, Function.identity()));
        return logList.stream().map(log -> {
            GameTencentMiniGameRoleRegisterVO vo = toVOSimple(log);
            if (StringUtils.isNotBlank(log.getAgentKey())) {
                AgentRpcVO agent = agentMap.get(log.getAgentKey());
                if (agent != null) {
                    vo.setAgentName(agent.getAgentName());
                }
            }
            return vo;
        }).collect(Collectors.toList());
    }

    private GameTencentMiniGameRoleRegisterVO toVOSimple(GameTencentMiniGameRoleRegister roleRegisterLog) {
        if (roleRegisterLog == null) {
            return null;
        }
        return BeanUtil.copy(roleRegisterLog, GameTencentMiniGameRoleRegisterVO.class);
    }

    private Tuple2<BackStatusEnum, String> doCallback(GameTencentMiniGameRoleRegister roleRegisterLog) {
        //最近的注册回传记录
        GameTencentMiniGameUser user = gameTencentMiniGameUserService.getOne(new LambdaQueryWrapper<GameTencentMiniGameUser>()
                .eq(GameTencentMiniGameUser::getGameId, roleRegisterLog.getGameId())
                .eq(GameTencentMiniGameUser::getWechatAppId, roleRegisterLog.getWechatAppId())
                .eq(GameTencentMiniGameUser::getWechatOpenid, roleRegisterLog.getWechatOpenid())
                .eq(GameTencentMiniGameUser::getAdAccountId, roleRegisterLog.getAdAccountId())
                .eq(GameTencentMiniGameUser::getBackType, BackTypeEnum.BACK_API.getBackType())
                .orderByDesc(GameTencentMiniGameUser::getCreateTime)
                .last("limit 1"));
        //回传策略
        GameBackPolicy gameBackPolicy = roleRegisterLog.getBackPolicyId() == null ? null
                : gameBackPolicyService.getById(roleRegisterLog.getBackPolicyId());

        //判断创角是否已成功回传
        if (this.roleBackCheck(roleRegisterLog)) {
            //新手引导回传
            this.tutorialFinishBack(roleRegisterLog, gameBackPolicy);
            //创角已回传
            return Tuple2.with(BackStatusEnum.NO, "创角已回传，默认不重复传");
        }

        //回传策略等级控制
        if (gameBackPolicy != null && gameBackPolicy.getRoleLevelMin() != null && roleRegisterLog.getRoleLevel() != null
                && roleRegisterLog.getRoleLevel() < gameBackPolicy.getRoleLevelMin()) {
            return Tuple2.with(BackStatusEnum.NO, "等级小于回传策略等级 " + gameBackPolicy.getRoleLevelMin() + "。不回传");
        }

        //判断注册是否成功回传
        if (user != null && !Objects.equals(BackStatusEnum.SUCCESS.getBackStatus(), user.getBackStatus())) {
            //执行注册回传
            gameTencentMiniGameUserService.userBack(user);
            //判断注册回传的时候是否合并了创角回传, 如果已经回传成功, 则不再回传
            if (this.roleBackCheck(roleRegisterLog)) {
                return Tuple2.with(BackStatusEnum.SUCCESS, "注册回传同步回传创角成功");
            }
        }

        //创角回传
        return gameTencentMiniGameBackLogService.roleRegisterBack(roleRegisterLog);
    }

    private boolean roleBackCheck(GameTencentMiniGameRoleRegister roleRegisterLog) {
        return gameTencentMiniGameBackLogService.count(new LambdaQueryWrapper<GameTencentMiniGameBackLog>()
                .eq(GameTencentMiniGameBackLog::getGameId, roleRegisterLog.getGameId())
                .eq(GameTencentMiniGameBackLog::getWechatAppId, roleRegisterLog.getWechatAppId())
                .eq(GameTencentMiniGameBackLog::getWechatOpenid, roleRegisterLog.getWechatOpenid())
                .eq(GameTencentMiniGameBackLog::getAdAccountId, roleRegisterLog.getAdAccountId())
                .eq(GameTencentMiniGameBackLog::getActionType, ActionTypeEnum.CREATE_ROLE.getActionType())
                .eq(GameTencentMiniGameBackLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
                .eq(GameTencentMiniGameBackLog::getBackType, BackTypeEnum.BACK_API.getBackType())
        ) > 0;
    }

    @Override
    public void tutorialFinishBack(GameTencentMiniGameRoleRegister roleRegisterLog, GameBackPolicy gameBackPolicy) {
        //角色判断完成新手引导回传
        if (gameTencentMiniGameBackLogService.count(new LambdaQueryWrapper<GameTencentMiniGameBackLog>()
                .eq(GameTencentMiniGameBackLog::getGameId, roleRegisterLog.getGameId())
                .eq(GameTencentMiniGameBackLog::getWechatAppId, roleRegisterLog.getWechatAppId())
                .eq(GameTencentMiniGameBackLog::getWechatOpenid, roleRegisterLog.getWechatOpenid())
                .eq(GameTencentMiniGameBackLog::getActionType, ActionTypeEnum.TUTORIAL_FINISH.getActionType())
                .eq(GameTencentMiniGameBackLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
        ) > 0) {
            return;
        }
        //回传策略不存在, 新手引导回传条件不存在, 不回传
        if (gameBackPolicy == null || Strings.isBlank(gameBackPolicy.getTutorialFinishJson())) {
            return;
        }
        //获取新手回传等级限制
        Long roleLevel = Optional.ofNullable(JsonUtil.toObj(gameBackPolicy.getTutorialFinishJson(), TutorialFinish.class))
                .map(TutorialFinish::getRoleLevel).orElse(null);
        //不满足等级条件判断, 不回传
        if (roleLevel != null && roleRegisterLog.getRoleLevel() < roleLevel) {
            return;
        }
        //执行完成新手引导回传
        BackStatusEnum backStatusEnum = gameTencentMiniGameBackLogService.tutorialFinishBack(roleRegisterLog).first;
        //更新新手引导回传状态更新
        super.update(new LambdaUpdateWrapper<GameTencentMiniGameRoleRegister>()
                .set(GameTencentMiniGameRoleRegister::getTutorialFinishBackStatus, backStatusEnum.getBackStatus())
                .eq(GameTencentMiniGameRoleRegister::getId, roleRegisterLog.getId()));
    }

    private BackStatusEnum doCallbackMediaSdk(GameTencentMiniGameRoleRegister roleRegisterLog) {
        GameTencentMiniGameUser user = gameTencentMiniGameUserService.getOne(new LambdaQueryWrapper<GameTencentMiniGameUser>()
                .eq(GameTencentMiniGameUser::getGameId, roleRegisterLog.getGameId())
                .eq(GameTencentMiniGameUser::getWechatAppId, roleRegisterLog.getWechatAppId())
                .eq(GameTencentMiniGameUser::getWechatOpenid, roleRegisterLog.getWechatOpenid())
                .eq(GameTencentMiniGameUser::getAdAccountId, roleRegisterLog.getAdAccountId())
                .eq(GameTencentMiniGameUser::getBackType, BackTypeEnum.BACK_MEDIA_SDK.getBackType())
                .orderByDesc(GameTencentMiniGameUser::getCreateTime)
                .last("limit 1"));
        if (user == null) {
            gameTencentMiniGameBackLogService.save(GameTencentMiniGameBackLog.builder()
                    .gameId(roleRegisterLog.getGameId())
                    .adAccountId(roleRegisterLog.getAdAccountId())
                    .clickId(roleRegisterLog.getClickId())
                    .actionTime(roleRegisterLog.getRegisterTime())
                    .wechatOpenid(roleRegisterLog.getWechatOpenid())
                    .wechatAppId(roleRegisterLog.getWechatAppId())
                    .actionType(ActionTypeEnum.CREATE_ROLE.getActionType())
                    .createTime(LocalDateTime.now())
                    .backStatus(BackStatusEnum.FAILED.getBackStatus())
                    .errMsg("找不到用户注册信息")
                    .backType(BackTypeEnum.BACK_MEDIA_SDK.getBackType())
                    .build());
            return BackStatusEnum.FAILED;
        }
        //判断创角是否回传
        if (gameTencentMiniGameBackLogService.count(new LambdaQueryWrapper<GameTencentMiniGameBackLog>()
                .eq(GameTencentMiniGameBackLog::getGameId, roleRegisterLog.getGameId())
                .eq(GameTencentMiniGameBackLog::getWechatAppId, roleRegisterLog.getWechatAppId())
                .eq(GameTencentMiniGameBackLog::getWechatOpenid, roleRegisterLog.getWechatOpenid())
                .eq(GameTencentMiniGameBackLog::getAdAccountId, roleRegisterLog.getAdAccountId())
                .eq(GameTencentMiniGameBackLog::getActionType, ActionTypeEnum.CREATE_ROLE.getActionType())
                .eq(GameTencentMiniGameBackLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
                .eq(GameTencentMiniGameBackLog::getBackType, BackTypeEnum.BACK_MEDIA_SDK.getBackType())
        ) > 0) {
            //创角已回传
            return BackStatusEnum.NO;
        }
        BackStatusEnum backStatus = BackStatusEnum.SUCCESS;
        gameTencentMiniGameBackLogService.save(GameTencentMiniGameBackLog.builder()
                .gameId(roleRegisterLog.getGameId())
                .adAccountId(roleRegisterLog.getAdAccountId())
                .clickId(roleRegisterLog.getClickId())
                .actionTime(roleRegisterLog.getRegisterTime())
                .wechatOpenid(roleRegisterLog.getWechatOpenid())
                .wechatAppId(roleRegisterLog.getWechatAppId())
                .actionType(ActionTypeEnum.CREATE_ROLE.getActionType())
                .createTime(LocalDateTime.now())
                .backStatus(backStatus.getBackStatus())
                .errMsg(null)
                .backType(BackTypeEnum.BACK_MEDIA_SDK.getBackType())
                .build());
        return backStatus;
    }
}
