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.zanxiang.advertising.tencent.base.AdvertisingTencentServer;
import com.zanxiang.advertising.tencent.base.pojo.dto.DataReportOfAppIdRpcDTO;
import com.zanxiang.advertising.tencent.base.pojo.dto.UserActionRpcDTO;
import com.zanxiang.advertising.tencent.base.rpc.IUserActionSetRpc;
import com.zanxiang.erp.base.ErpServer;
import com.zanxiang.erp.base.rpc.ISysUserRpc;
import com.zanxiang.game.back.serve.dao.mapper.GameTencentRoleRegisterMapper;
import com.zanxiang.game.back.serve.pojo.dto.GameTencentRoleRegisterDTO;
import com.zanxiang.game.back.serve.pojo.entity.GameBackPolicy;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentBackLog;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentRoleRegister;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentUser;
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.vo.GameTencentRoleRegisterVO;
import com.zanxiang.game.back.serve.service.IGameBackPolicyService;
import com.zanxiang.game.back.serve.service.IGameTencentBackLogService;
import com.zanxiang.game.back.serve.service.IGameTencentRoleRegisterService;
import com.zanxiang.game.back.serve.service.IGameTencentUserService;
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.bean.BeanUtil;
import com.zanxiang.module.util.pojo.ResultVO;
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.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 GameTencentRoleRegisterServiceImpl extends ServiceImpl<GameTencentRoleRegisterMapper, GameTencentRoleRegister>
        implements IGameTencentRoleRegisterService {

    @DubboReference(providedBy = AdvertisingTencentServer.SERVER_DUBBO_NAME)
    private IUserActionSetRpc userActionSetRpc;
    @DubboReference(providedBy = ErpServer.SERVER_DUBBO_NAME)
    private ISysUserRpc sysUserRpc;
    @Autowired
    private IGameBackPolicyService gameBackPolicyService;
    @Autowired
    private IGameTencentBackLogService gameTencentBackLogService;
    @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)
    private IAgentRpc agentRpc;
    @Autowired
    private IGameTencentUserService gameTencentUserService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean roleRegisterBack(GameTencentRoleRegister roleRegisterLog) {
        BackStatusEnum backStatus = doCallback(roleRegisterLog);
        return update(new LambdaUpdateWrapper<GameTencentRoleRegister>()
                .set(GameTencentRoleRegister::getIsBack, backStatus.getBackStatus())
                .eq(GameTencentRoleRegister::getId, roleRegisterLog.getId())
        );
    }


    @Override
    public IPage<GameTencentRoleRegisterVO> tencentLogList(GameTencentRoleRegisterDTO dto) {
        IPage<GameTencentRoleRegister> page = page(dto.toPage(), new LambdaQueryWrapper<GameTencentRoleRegister>()
                .eq(StringUtils.isNotBlank(dto.getChannel()), GameTencentRoleRegister::getChannel, dto.getChannel())
                .ge(dto.getRegisterBegin() != null, GameTencentRoleRegister::getRegisterTime, dto.getRegisterBegin() == null ? null : LocalDateTime.of(dto.getRegisterBegin(), LocalTime.MIDNIGHT))
                .le(dto.getRegisterEnd() != null, GameTencentRoleRegister::getRegisterTime, dto.getRegisterEnd() == null ? null : LocalDateTime.of(dto.getRegisterEnd(), LocalTime.MAX))
                .eq(null != dto.getGameId(), GameTencentRoleRegister::getGameId, dto.getGameId())
                .eq(null != dto.getAdAccountId(), GameTencentRoleRegister::getAdAccountId, dto.getAdAccountId())
                .eq(StringUtils.isNotBlank(dto.getWechatAppId()), GameTencentRoleRegister::getWechatAppId, dto.getWechatAppId())
                .eq(StringUtils.isNotBlank(dto.getWechatOpenid()), GameTencentRoleRegister::getWechatOpenid, dto.getWechatOpenid())
                .eq(null != dto.getIsBack(), GameTencentRoleRegister::getIsBack, dto.getIsBack())
                .orderByDesc(GameTencentRoleRegister::getCreateTime)
        );

        IPage<GameTencentRoleRegisterVO> 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 tencentUserReport(List<Long> ids) {
        listByIds(ids).forEach(roleRegisterLog -> {
            BackStatusEnum backStatus = doCallback(roleRegisterLog);
            update(new LambdaUpdateWrapper<GameTencentRoleRegister>()
                    .set(GameTencentRoleRegister::getIsBack, backStatus.getBackStatus())
                    .eq(GameTencentRoleRegister::getId, roleRegisterLog.getId())
            );
        });
        return true;
    }

    private List<GameTencentRoleRegisterVO> toVOBatch(List<GameTencentRoleRegister> logList) {
        if (CollectionUtils.isEmpty(logList)) {
            return Collections.emptyList();
        }
        Set<String> agentKeys = logList.stream().map(GameTencentRoleRegister::getChannel).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 -> {
            GameTencentRoleRegisterVO vo = BeanUtil.copy(log, GameTencentRoleRegisterVO.class);
            if (StringUtils.isNotBlank(log.getChannel())) {
                AgentRpcVO agent = agentMap.get(log.getChannel());
                if (agent != null) {
                    vo.setAgentName(agent.getAgentName());
                }
            }
            return vo;
        }).collect(Collectors.toList());

    }


    private BackStatusEnum doCallback(GameTencentRoleRegister roleRegisterLog) {
        if (roleRegisterLog.getBackPolicyId() != null) {
            GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(roleRegisterLog.getBackPolicyId());
            if (gameBackPolicy.getRoleLevelMin() != null && roleRegisterLog.getRoleLevel() != null
                    && roleRegisterLog.getRoleLevel() < gameBackPolicy.getRoleLevelMin()) {
                return BackStatusEnum.NO;
            }
        }

        GameTencentUser user = gameTencentUserService.getOne(new LambdaQueryWrapper<GameTencentUser>()
                .eq(GameTencentUser::getGameId, roleRegisterLog.getGameId())
                .eq(GameTencentUser::getWechatAppId, roleRegisterLog.getWechatAppId())
                .eq(GameTencentUser::getWechatOpenid, roleRegisterLog.getWechatOpenid())
                .eq(GameTencentUser::getAdAccountId, roleRegisterLog.getAdAccountId())
                .orderByDesc(GameTencentUser::getCreateTime)
                .last("limit 1")
        );
        if (user != null) {
            if (BackStatusEnum.NO.getBackStatus().equals(user.getIsBack())) {
                gameTencentUserService.userBack(user, true);
            } else {
                // 注册已回传，则默认认为创角也回传了
                return BackStatusEnum.NO;
            }
        }

        Map<String, Object> actionParam = new HashMap<>(2);
        actionParam.put("claim_type", 0);
        DataReportOfAppIdRpcDTO dataReportOfAppIdRpcDTO = DataReportOfAppIdRpcDTO.builder()
                .appId(roleRegisterLog.getWechatAppId())
                .userActionSetId(roleRegisterLog.getUserActionSetId())
                .action(UserActionRpcDTO.builder()
                        .actionTime(roleRegisterLog.getRegisterTime())
                        .actionType(ActionTypeEnum.CREATE_ROLE.getActionType())
                        .userId(UserActionRpcDTO.UserIdRpcDTO.builder()
                                .wechatAppId(roleRegisterLog.getWechatAppId())
                                .wechatOpenid(roleRegisterLog.getWechatOpenid())
                                .build())
                        .actionParam(actionParam)
                        .build())
                .build();

        GameTencentBackLog gameTencentBackLog = GameTencentBackLog.builder()
                .gameId(roleRegisterLog.getGameId())
                .adAccountId(roleRegisterLog.getAdAccountId())
                .actionTime(roleRegisterLog.getRegisterTime())
                .createTime(LocalDateTime.now())
                .actionType(ActionTypeEnum.CREATE_ROLE.getActionType())
                .wechatAppId(roleRegisterLog.getWechatAppId())
                .wechatOpenid(roleRegisterLog.getWechatOpenid())
                .userActionSetId(roleRegisterLog.getUserActionSetId())
                .actionParam(actionParam.toString())
                .build();
        ResultVO<Boolean> result = userActionSetRpc.reportByAppId(dataReportOfAppIdRpcDTO);
        BackStatusEnum backStatus = BackStatusEnum.FAILED;
        if (result.isSuccess()) {
            backStatus = BackStatusEnum.SUCCESS;
            gameTencentBackLog.setBackLog("回传成功");
        } else {
            gameTencentBackLog.setBackLog(result.getMsg());
        }
        gameTencentBackLogService.save(gameTencentBackLog);
        return backStatus;
    }
}
