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

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.red.circle.common.business.enums.SendPropsOrigin;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.external.inner.endpoint.message.OfficialNoticeClient;
import com.red.circle.external.inner.model.cmd.message.notice.official.NoticeExtTemplateCustomizeCmd;
import com.red.circle.external.inner.model.enums.message.OfficialNoticeTypeEnum;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.command.user.ManagerApprovalNotPassCmdExe;
import com.red.circle.other.app.command.user.query.RoomManagerAuthsQueryExe;
import com.red.circle.other.app.dto.clientobject.user.RoomManagerAuthsCO;
import com.red.circle.other.app.dto.clientobject.user.user.UserManagerAuthsCO;
import com.red.circle.other.app.dto.cmd.material.PropsGiveAwayCmd;
import com.red.circle.other.app.dto.cmd.material.PropsStoreTypeQryCmd;
import com.red.circle.other.app.dto.cmd.user.ManagerApprovalCmd;
import com.red.circle.other.app.dto.cmd.user.RoomManageCommonCmd;
import com.red.circle.other.app.scheduler.MyAmazingBot;
import com.red.circle.other.domain.model.user.ability.RegionConfig;
import com.red.circle.other.infra.database.rds.service.sys.AdministratorAuthService;
import com.red.circle.other.infra.utils.I18nUtils;
import com.red.circle.other.domain.gateway.props.PropsNobleVipGateway;
import com.red.circle.other.domain.gateway.props.PropsStoreGateway;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.infra.convertor.material.PropsMaterialInfraConvertor;
import com.red.circle.other.infra.database.cache.key.AdminFreeKeys;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamProfile;
import com.red.circle.other.infra.database.mongo.entity.user.profile.UserSpecialId;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamProfileService;
import com.red.circle.other.infra.database.mongo.service.user.profile.UserSpecialIdService;
import com.red.circle.other.infra.database.rds.entity.props.PropsSourceRecord;
import com.red.circle.other.infra.database.rds.entity.sys.Administrator;
import com.red.circle.other.infra.database.rds.entity.team.BusinessDevelopmentBaseInfo;
import com.red.circle.other.infra.database.rds.entity.team.BusinessDevelopmentTeam;
import com.red.circle.other.infra.database.rds.service.props.PropsSourceRecordService;
import com.red.circle.other.infra.database.rds.service.sys.AdministratorService;
import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentBaseInfoService;
import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentTeamService;
import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.endpoint.material.props.PropsBackpackClient;
import com.red.circle.other.inner.endpoint.material.props.PropsNobleVipClient;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import com.red.circle.other.inner.enums.material.ConsolePropsTypeEnum;
import com.red.circle.other.inner.enums.material.PropsCommodityType;
import com.red.circle.other.inner.enums.team.TeamMemberRole;
import com.red.circle.other.inner.model.cmd.material.GivePropsBackpackCmd;
import com.red.circle.other.inner.model.cmd.team.TeamMemberBackQryCmd;
import com.red.circle.other.inner.model.dto.material.PropsResourcesDTO;
import com.red.circle.other.inner.model.dto.material.props.NobleVipAbility;
import com.red.circle.other.inner.model.dto.material.props.PropsNobleVipAbilityDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.text.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 管理员权限服务 实现.
 *
 * @author pengliang on 2021/4/6
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ManagerAuthServiceImpl implements ManagerAuthService {

    private final RoomManagerAuthsQueryExe roomManagerAuthsQueryExe;
    private final ManagerApprovalNotPassCmdExe managerApprovalNotPassCmdExe;
    private final PropsSourceRecordService propsSourceRecordService;
    private final AdministratorService administratorService;
    private final PropsMaterialInfraConvertor propsMaterialInfraConvertor;
    private final UserProfileGateway userProfileGateway;
    private final UserRegionGateway userRegionGateway;
    private final RedisService redisService;
    private final PropsBackpackClient propsBackpackClient;
    private final PropsStoreGateway propsStoreGateway;
    private final BusinessDevelopmentBaseInfoService businessDevelopmentBaseInfoService;
    private final TeamMemberService teamMemberService;
    private final TeamProfileService teamProfileService;
    private final UserSpecialIdService userSpecialIdService;
    private final PropsNobleVipGateway propsNobleVipGateway;
    private final UserProfileClient userProfileClient;
    private final OfficialNoticeClient officialNoticeClient;
    private final AdministratorAuthService administratorAuthService;
    private final PropsNobleVipClient propsNobleVipClient;

    @Override
    public RoomManagerAuthsCO managerAuths(RoomManageCommonCmd roomManageCommonCmd) {
        return roomManagerAuthsQueryExe.execute(roomManageCommonCmd);
    }

    @Override
    public void approval(ManagerApprovalCmd cmd) {
        managerApprovalNotPassCmdExe.execute(cmd);
    }

    @Override
    public List<PropsResourcesDTO> propsList(PropsStoreTypeQryCmd cmd) {
        Administrator administrator = administratorService
                .getByUserId(cmd.requiredReqUserId());

        if (Objects.isNull(administrator) || !Objects.equals(administrator.getStatus(), Boolean.TRUE)) {
            ResponseAssert.failure(CommonErrorCode.SEND_FAILURE,
                    "user is not admin.");
        }

//        String redisKey = AdminFreeKeys.ADMIN_FREE_PROPS.getKey(cmd.requiredReqUserId());
//        List<String> redisResult = redisService.hashGetValues(redisKey);
        List<String> authResources = administratorAuthService.listAuthResources(cmd.requiredReqUserId());
        // 查询用户是否有赠送所有座驾/VIP的权限
        boolean isHaveAuth = isIsHaveAuth(cmd);
//        if (CollectionUtils.isEmpty(redisResult)) {
        List<PropsSourceRecord> result = propsSourceRecordService.adminFreePropsList(isHaveAuth);
        List<PropsResourcesDTO> resultDto = result.stream().map(action -> {
            PropsResourcesDTO dto = propsMaterialInfraConvertor.toPropsResourcesDTO(action);
            dto.setUserId(administrator.getUserId());
            dto.setIsSendUniqueId(authResources.contains("SEND_SPECIAL_ID"));
            dto.setIsResetPassword(authResources.contains("RESET_PASSWORD"));
            dto.setCount(50);
            return dto;
        }).toList();

        Set<Long> sourceIds = resultDto.stream().filter(filter -> filter.getType().equals(cmd.getPropsType().name()))
            .map(PropsResourcesDTO::getId).collect(Collectors.toSet());

        // 贵族携带资源信息只有vip1 2 3
        Map<Long, NobleVipAbility> abilityMap =
            Objects.equals(cmd.getPropsType().name(), ConsolePropsTypeEnum.NOBLE_VIP.name())
                ? ResponseAssert.requiredSuccess(propsNobleVipClient.mapAbilityByIds(sourceIds))
                : CollectionUtils.newHashMap();
        if (MapUtil.isNotEmpty(abilityMap)) {
          Set<Long> collect = abilityMap.entrySet().stream()
              .filter(entry -> entry.getValue().getVipLevel() <= 3)
              .map(Map.Entry::getKey).collect(Collectors.toSet());
          return resultDto.stream().filter(e -> collect.contains(e.getId())).toList();
        }

      return resultDto.stream().filter(e -> sourceIds.contains(e.getId())).toList();
    }

    private boolean isIsHaveAuth(PropsStoreTypeQryCmd cmd) {
        List<String> authResources = administratorAuthService.listAuthResources(cmd.requiredReqUserId());
        boolean isHaveAuth = false;
        if (PropsCommodityType.RIDE.equals(cmd.getPropsType())) {
            isHaveAuth = authResources.contains("ALL_VEHICLE");
        }
        if (PropsCommodityType.NOBLE_VIP.equals(cmd.getPropsType())) {
            isHaveAuth = authResources.contains("ALL_VIP");
        }
        return isHaveAuth;
    }

    public static boolean validateString(String input) {
        if (StringUtils.isBlank(input)) {
            return false;
        }
        String lowerCaseInput = input.toLowerCase();
        return !(lowerCaseInput.contains("manager") ||
                lowerCaseInput.contains("likei") ||
                lowerCaseInput.contains("official"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendProps(PropsGiveAwayCmd cmd) {
        Administrator administrator = administratorService
                .getByUserId(cmd.requiredReqUserId());

        if (Objects.isNull(administrator) || !Objects.equals(administrator.getStatus(), Boolean.TRUE)) {
            ResponseAssert.failure(CommonErrorCode.SEND_FAILURE,
                    "user is not admin.");
        }
        if (Objects.isNull(cmd.getAcceptUserId())) {
            ResponseAssert.failure(CommonErrorCode.SEND_FAILURE,
                    "acceptUserId is not null.");
        }
        // 国家不一样不能赠送
        if (!userRegionGateway.checkEqRegion(cmd.getAcceptUserId(), cmd.requiredReqUserId())) {

            ResponseAssert.failure(CommonErrorCode.SEND_FAILURE,
                    "country are different.");

        }
        String redisKey = AdminFreeKeys.ADMIN_FREE_PROPS.getKey(cmd.requiredReqUserId());
        try {
            if (redisService.lock(redisKey, 20)) {
                if (cmd.isSpecialId()) {
                    List<String> authResources = administratorAuthService.listAuthResources(cmd.requiredReqUserId());
                    ResponseAssert.isTrue(CommonErrorCode.INSUFFICIENT_PERMISSION, authResources.contains("SEND_SPECIAL_ID"));
                    // 是否有赠送靓号(2-8位)的权限
                    boolean isHaveAuth = authResources.contains("SEND_ID");
                    // 去掉原本逻辑，赠送靓号，不限制团队、位数大于等于4位小于等于8位即可
                    if (!validateString(cmd.getSpecialAccount())) {
                        ResponseAssert.failure(CommonErrorCode.SEND_FAILURE, "Rules don't match");
                    }
                    boolean isAccount = cmd.getSpecialAccount().length() >= 4 && cmd.getSpecialAccount().length() <= 8;
                    boolean isAccountTwo = cmd.getSpecialAccount().length() >= 2 && cmd.getSpecialAccount().length() <= 8;
                    if (!isHaveAuth && !isAccount) {
                        ResponseAssert.failure(CommonErrorCode.SEND_FAILURE, "Rules don't match");
                    }
                    if (isHaveAuth && !isAccountTwo) {
                        ResponseAssert.failure(CommonErrorCode.SEND_FAILURE, "Rules don't match");
                    }
                    createSpecialId(cmd);
                    /**
                    //靓号单独处理
                    List<BusinessDevelopmentBaseInfo> bdList = businessDevelopmentBaseInfoService.listBdByLeadUserId(cmd.requiredReqUserId());
                    //判断 cmd.getAcceptUserId() 是否在 bdList 中
                    if (bdList.stream().anyMatch(action -> Objects.equals(action.getUserId(), cmd.getAcceptUserId()))) {
                        //是bd 送四位数靓号 判断cmd.account长度是否是4位数
                        if (StringUtils.isBlank(cmd.getSpecialAccount()) || cmd.getSpecialAccount().length() != 4) {
                            ResponseAssert.failure(CommonErrorCode.SEND_FAILURE, "Rules don't match");
                        }
                        createSpecialId(cmd);
                        return;
                    }


                    boolean inTeam = false;
                    for (BusinessDevelopmentBaseInfo action : bdList) {
                        // 不是BD，检查是否在团队中  agent
                        List<BusinessDevelopmentTeam> agents = businessDevelopmentTeamService.query()
                                .eq(BusinessDevelopmentTeam::getUserId, action.getUserId()).list();


                        for (BusinessDevelopmentTeam agent : agents) {
                            TeamProfile byOwnUserId = teamProfileService.getByOwnUserId(agent.getAgentId());
                            if (!Objects.isNull(byOwnUserId)) {


                                List<TeamMember> teamMembers = teamMemberService.listTeamMember(
                                        new TeamMemberBackQryCmd().setTeamId(byOwnUserId.getId())
                                );
                                //如果存在 接收人id 是否在团队中  rule 是 OWN 是五位数  member 是6位数的判断

                                if (teamMembers.stream().anyMatch(member -> Objects.equals(member.getRole().name(), TeamMemberRole.OWN.name()) &&
                                        Objects.equals(member.getMemberId(), cmd.getAcceptUserId()))) {
//                                    if (byOwnUserId.getOwnUserId().equals(cmd.requiredReqUserId())) {
                                        //代理五位数靓号
                                        if (StringUtils.isBlank(cmd.getSpecialAccount()) || cmd.getSpecialAccount().length() != 5) {
                                            ResponseAssert.failure(CommonErrorCode.SEND_FAILURE, "Rules don't match");
                                        }
                                        createSpecialId(cmd);
                                        inTeam = true;
                                        break;
//                                    }

                                }
                                if (teamMembers.stream().anyMatch(member -> Objects.equals(member.getRole().name(), TeamMemberRole.MEMBER.name()) &&
                                        Objects.equals(member.getMemberId(), cmd.getAcceptUserId()))) {
                                    //存在 6位数id 赠送逻辑
                                    if (StringUtils.isBlank(cmd.getSpecialAccount()) || cmd.getSpecialAccount().length() != 6) {
                                        ResponseAssert.failure(CommonErrorCode.SEND_FAILURE, "Rules don't match");
                                    }
                                    createSpecialId(cmd);
                                    inTeam = true;
                                    break;
                                }
                            }
                        }
                    }

                    // 如果既不是BD也不在任何团队中，则返回错误
                    if (!inTeam) {
                        ResponseAssert.failure(UserErrorCode.NOT_IN_TEAM, "Not in team.");
                    }


                    //赠送逻辑
                    **/

                } else {
                    //道具赠送

                    PropsSourceRecord propsSourceRecord = propsSourceRecordService.getById(cmd.getPropsId());
                    //赠送的道具默认为7天
                    if (Objects.isNull(propsSourceRecord)) {
                        ResponseAssert.failure(CommonErrorCode.SEND_FAILURE,
                                "propsId is not null.");
                    }


//        UserProfile user = userProfileGateway.getByUserId(cmd.getAcceptUserId());
//        if (Objects.isNull(user)) {
//            ResponseAssert.failure(CommonErrorCode.SEND_FAILURE,
//                    "accept user is not null.");
//        }
//
//        UserProfile admin = userProfileGateway.getByUserId(cmd.requiredReqUserId());


                  int days = PropsCommodityType.NOBLE_VIP.name().equals(propsSourceRecord.getType()) ? 3 : 7;
                  sendPropsRecord(cmd, propsSourceRecord.getType(), days);
                    //vip单独处理
                    if (propsSourceRecord.getType().equals(PropsCommodityType.NOBLE_VIP.name())) {
                        PropsNobleVipAbilityDTO vipAbility = propsNobleVipGateway.getAbilityDTO(propsSourceRecord.getId());
                        if (Objects.nonNull(vipAbility.getCarId()) && !Objects
                                .equals(vipAbility.getCarId(), 0L)) {

                            cmd.setPropsId(vipAbility.getCarId());
                            sendPropsRecord(cmd, ConsolePropsTypeEnum.RIDE.getName(), 3);
                        }

                        if (Objects.nonNull(vipAbility.getAvatarFrameId())
                                && !Objects.equals(vipAbility.getAvatarFrameId(), 0L)) {
                            cmd.setPropsId(vipAbility.getAvatarFrameId());
                            sendPropsRecord(cmd, ConsolePropsTypeEnum.AVATAR_FRAME.getName(), 3);
                        }

                        if (Objects.nonNull(vipAbility.getChatBubbleId())
                                && !Objects.equals(vipAbility.getChatBubbleId(), 0L)) {
                            cmd.setPropsId(vipAbility.getChatBubbleId());
                            sendPropsRecord(cmd, ConsolePropsTypeEnum.CHAT_BUBBLE.getName(), 3);
                        }

                        if (Objects.nonNull(vipAbility.getDataCardId())
                                && !Objects.equals(vipAbility.getDataCardId(), 0L)) {
                            cmd.setPropsId(vipAbility.getDataCardId());
                            sendPropsRecord(cmd, ConsolePropsTypeEnum.DATA_CARD.getName(), 3);
                        }

                        // 使用最大等级的VIP
                        useMaxNobleVip(cmd.getAcceptUserId());
                    }

                }

                /**
                //库存-1
                List<String> redisResult = redisService.hashGetValues(redisKey);
                if (!Objects.isNull(redisResult)) {
                    redisResult.stream().map(map -> JSON.parseObject(map, PropsResourcesDTO.class)).forEach(record -> {
                        if (record.getId().equals(cmd.getPropsId())) {
                            record.setCount(record.getCount() - 1);
                            redisService.hashPut(redisKey, String.valueOf(record.getId()), record);
                            log.info("admin  free props end, record.{}", record);
                        }
                    });
                }
                 **/
            }

        } finally {
            redisService.unlock(redisKey);
        }
    }

    @Override
    public UserManagerAuthsCO userAuths(Long userId) {
        List<String> authResources = administratorAuthService.listAuthResources(userId);
        UserManagerAuthsCO userManagerAuths = new UserManagerAuthsCO();
        userManagerAuths.setIsSendUniqueId(authResources.contains("SEND_SPECIAL_ID"));
        userManagerAuths.setIsResetPassword(authResources.contains("RESET_PASSWORD"));
        return userManagerAuths;
    }

    private void useMaxNobleVip(Long receiverId) {
      PropsNobleVipAbilityDTO abilityDTO = propsNobleVipClient.getUserMaxAbilityDTO(receiverId).getBody();
      if (Objects.isNull(abilityDTO)) {
        return;
      }
      propsBackpackClient.switchUseProps(receiverId, abilityDTO.getId());
      propsBackpackClient.switchUseProps(receiverId, abilityDTO.getAvatarFrameId());
      propsBackpackClient.switchUseProps(receiverId, abilityDTO.getDataCardId());
      propsBackpackClient.switchUseProps(receiverId, abilityDTO.getCarId());
      userProfileClient.removeCacheAll(receiverId);
    }

    private void sendPropsRecord(PropsGiveAwayCmd cmd, String sourceType, Integer days) {
        //开始赠送道具
        log.info("admin  free props start.{}", cmd);
//                赠送的都是7天
        propsBackpackClient.giveProps(new GivePropsBackpackCmd()
                .setAcceptUserId(cmd.getAcceptUserId())
                .setPropsId(cmd.getPropsId())
                .setType(sourceType)
                .setOrigin(SendPropsOrigin.ADMIN_FREE.name())
                .setOriginDesc(SendPropsOrigin.ADMIN_FREE.getDesc())
                .setDays(days)
                .setUseProps(Boolean.TRUE)
                .setAllowGive(Boolean.FALSE)
                .setOpUser(cmd.requiredReqUserId()));
        try {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(cmd.requiredReqUserId())
                    .append(" 赠送 ")
                    .append(cmd.getPropsId())
                    .append(" 道具 给 ").append(cmd.getAcceptUserId());
//            sendTelegram(stringBuilder);
        } catch (Exception e) {
            log.error("赠送道具 发送机器人失败", e);
        }
        RegionConfig region = userRegionGateway.getRegionConfigByUserId(cmd.getAcceptUserId());
        if (region == null) {
            return;
        }

      String url = null;
      PropsSourceRecord props = propsSourceRecordService.getPropsById(cmd.getPropsId());
      if (props != null) {
        url = props.getCover();
      }

      Map<String, Object> map = new HashMap<>();
      map.put("propType", sourceType);
      officialNoticeClient.send(
                NoticeExtTemplateCustomizeCmd.builder().toAccount(cmd.getAcceptUserId())
                        .noticeType(OfficialNoticeTypeEnum.GIVE_AWAY_PROPS)
                        .content(I18nUtils.getPropsRewardContent(sourceType, days, I18nUtils.getLanguageByRegion(region.getRegionName())))
                        .title(JSON.toJSONString(map))
                        .expand(url)
                        .build());
    }


    //创建靓号方法
    public void createSpecialId(PropsGiveAwayCmd cmd) {
        // 检查用户是否已有靓号
        UserSpecialId oldSpecialId = userSpecialIdService.getByUserId(cmd.getAcceptUserId());
        // 检查靓号是否已存在
        boolean exists = userSpecialIdService.exists(cmd.getReqSysOrigin().getOrigin(), cmd.getSpecialAccount());
        if (oldSpecialId != null && (!exists || oldSpecialId.getAccount().equals(cmd.getSpecialAccount()))) {
            userSpecialIdService.remove(oldSpecialId.getId());
        }

        if (oldSpecialId == null) {
            ResponseAssert.isFalse(CommonErrorCode.SAVE_FAILURE, "The special id already exists", exists);
        } else {
            log.info("true or false.{}", !oldSpecialId.getAccount().equals(cmd.getSpecialAccount()));
            ResponseAssert.isFalse(CommonErrorCode.SAVE_FAILURE, "The special id already exists",
                    exists && !oldSpecialId.getAccount().equals(cmd.getSpecialAccount()));
        }
        // 创建新靓号
        UserSpecialId specialIdCmd = getUserSpecialId(cmd);
        userSpecialIdService.add(specialIdCmd);

        try {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(cmd.requiredReqUserId())
                    .append(" 赠送 ")
                    .append(cmd.getSpecialAccount())
                    .append(" 靓号 给 ").append(cmd.getAcceptUserId());
//            sendTelegram(stringBuilder);
        } catch (Exception e) {
            log.error("赠送靓号 发送机器人失败", e);
        }

        log.info(" admin赠送 靓号成功, adminId{}, userId:{}, account:{}", cmd.requiredReqUserId(), cmd.getAcceptUserId(), cmd.getSpecialAccount());
        //发奖通知
        //Received gifts from Duoduo
        RegionConfig region = userRegionGateway.getRegionConfigByUserId(cmd.getAcceptUserId());
        if (region == null) {
            return;
        }
        /*officialNoticeClient.send(
                NoticeExtTemplateCustomizeCmd.builder().toAccount(cmd.getAcceptUserId())
                        .noticeType(OfficialNoticeTypeEnum.GIVE_AWAY_PROPS)
                        .content(I18nUtils.getPropsRewardContent(ConsolePropsTypeEnum.SPECIAL_ID.getName(), 30, I18nUtils.getLanguageByRegion(region.getRegionName())))
                        .expand(null)
                        .build());*/

    }

    @NotNull
    private static UserSpecialId getUserSpecialId(PropsGiveAwayCmd cmd) {
        UserSpecialId specialIdCmd = new UserSpecialId();
        specialIdCmd.setSysOrigin(cmd.getReqSysOrigin().getOrigin());
        specialIdCmd.setAccount(cmd.getSpecialAccount());
        specialIdCmd.setUserId(cmd.getAcceptUserId());
        // 30天 admin 赠送
        specialIdCmd.setExpiredTime(TimestampUtils.dateTimePlusDays(TimestampUtils.now(), 30));
        return specialIdCmd;
    }

    private void sendTelegram(StringBuilder stringBuilder) {
        //机器人来咯
        MyAmazingBot myAmazingBot = new MyAmazingBot();
        myAmazingBot.sendMsg("-473742590", stringBuilder.toString());
    }

}
