package com.ruoyi.cai.manager;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.cai.domain.*;
import com.ruoyi.cai.dto.admin.UserForbidDTO;
import com.ruoyi.cai.dto.admin.query.UserForbidReq;
import com.ruoyi.cai.enums.ForbidTimeEnum;
import com.ruoyi.cai.enums.ForbidTypeEnum;
import com.ruoyi.cai.mq.AmqpProducer;
import com.ruoyi.cai.mq.dto.CommonDelayDto;
import com.ruoyi.cai.service.*;
import com.ruoyi.common.utils.StringUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;

@Component
@Slf4j
public class UserForbidManager {
    @Autowired
    private UserForbidLogService userForbidLogService;
    @Autowired
    private UserForbidService userForbidService;
    @Autowired
    private UserService userService;
    @Autowired
    private ForbidCache forbidCache;
    @Autowired
    private ForbidFilterService forbidFilterService;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private AnchorService anchorService;

    public void batchForbid(UserForbidReq userForbidReq){
        List<Integer> type = userForbidReq.getType();
        User user = userService.getById(userForbidReq.getUserId());
        for (Integer integer : type) {
            if(integer == 1){ // 封用户
                UserForbidDTO dto = new UserForbidDTO();
                dto.setForbidTime(userForbidReq.getForbidTime());
                dto.setForbidType(ForbidTypeEnum.USER.getCode());
                dto.setMember(user.getUsercode());
                dto.setRemark(userForbidReq.getReason());
                this.forbid(dto);
            }else if(integer == 2){ // 封设备
                // 封设备
            }else if(integer == 3){ // 封IP
                UserInfo userInfo = userInfoService.getByUserId(user.getId());
                UserForbidDTO dto = new UserForbidDTO();
                dto.setForbidTime(userForbidReq.getForbidTime());
                dto.setForbidType(ForbidTypeEnum.IP.getCode());
                dto.setMember(userInfo.getLastLoginIp());
                dto.setRemark(userForbidReq.getReason());
                this.forbid(dto);
            }
        }
    }

    /**
     * 封禁总入口
     */
    public void forbid(UserForbidDTO userForbidDTO){
        ForbidTimeEnum forbidTime = ForbidTimeEnum.getByCode(userForbidDTO.getForbidTime());
        ForbidTypeEnum forbidType = ForbidTypeEnum.getByCode(userForbidDTO.getForbidType());
        if(forbidTime == null || forbidType == null){
            log.error("封禁入参错误 data={}", JSON.toJSONString(userForbidDTO));
            return;
        }
        User user = null;
        if(forbidType == ForbidTypeEnum.USER){
            user = userService.getByUserCode(userForbidDTO.getMember());
            if(user == null){
                return;
            }
        }
        UserForbidLog userForbidLog = new UserForbidLog();
        userForbidLog.setType(userForbidDTO.getForbidType());
        userForbidLog.setMember(userForbidDTO.getMember());
        userForbidLog.setForbidTime(userForbidDTO.getForbidTime());
        userForbidLog.setReason(userForbidDTO.getRemark());
        userForbidLogService.save(userForbidLog);
        userForbidService.forbid(userForbidLog,user);
    }

    public CheckForbid checkForbid(Long userId,String usercode, String IMEI, String ip){
        ForbidTypeEnum typeEnum;
        CheckForbid noForbid = CheckForbid.noForbid();
        String member;
        Long forbidId;
        if(StringUtils.isNotEmpty(usercode)){
            forbidId = forbidCache.checkForbid(usercode, ForbidTypeEnum.USER);
            if(forbidId == null){
                return noForbid;
            }
            member = usercode;
            typeEnum = ForbidTypeEnum.USER;
            String traceId = IdManager.nextIdStr();
            noForbid = CheckForbid.forbid(traceId);
            noForbid.setMessage("您的账号已被封禁");

        }else if(IMEI != null){
            forbidId = forbidCache.checkForbid(IMEI, ForbidTypeEnum.IMEI);
            if(forbidId == null){
                return noForbid;
            }
            member = IMEI;
            typeEnum = ForbidTypeEnum.IMEI;
            String traceId = IdManager.nextIdStr();
            noForbid = CheckForbid.forbid(traceId);
            noForbid.setMessage("您的设备已被封禁");
        }else if(ip != null){
            forbidId = forbidCache.checkForbid(ip, ForbidTypeEnum.IP);
            if(forbidId == null){
                return noForbid;
            }
            member = ip;
            typeEnum = ForbidTypeEnum.IP;
            String traceId = IdManager.nextIdStr();
            noForbid = CheckForbid.forbid(traceId);
            noForbid.setMessage("您的IP已被封禁");
        }else{
            return noForbid;
        }
        if(noForbid.isForbid()){
            // 保存拦截记录
            ForbidFilter filter = new ForbidFilter();
            filter.setType(typeEnum.getCode());
            filter.setMember(member);
            filter.setUserId(userId);
            filter.setTraceNo(noForbid.getTraceId());
            filter.setForbidId(forbidId);
            filter.setFilterReason(noForbid.getMessage());
            forbidFilterService.addForbidFilter(filter);
        }
        return noForbid;
    }

    @Transactional(rollbackFor = Exception.class)
    public void unForbidByForbidId(Long id) {
        UserForbid userForbid = userForbidService.getById(id);
        userForbidService.update(Wrappers.lambdaUpdate(UserForbid.class)
                .eq(UserForbid::getId,userForbid.getId())
                .set(UserForbid::getForbidStatus,2));
        if(ForbidTypeEnum.USER.getCode().equals(userForbid.getType())){
            User user = userService.getByUserCode(userForbid.getMember());
            userService.update(Wrappers.lambdaUpdate(User.class).eq(User::getId,user.getId()).set(User::getStatus,0));
            anchorService.update(Wrappers.lambdaUpdate(Anchor.class).eq(Anchor::getId,user.getId()).set(Anchor::getStatus,0));
        }
        this.unForbid(userForbid.getType(),userForbid.getMember());
    }

    public void unForbid(Integer type,String member){
        forbidCache.unForbid(type,member);
    }

    public void checkAll(){
        List<Long> expireIds = new ArrayList<>();
        List<Long> expireConsumer = new ArrayList<>();
        Page<UserForbid> page = new Page<>();
        page.setSize(100L);
        long current = 0;
        while (true){
            current++;
            page.setCurrent(current);
            Page<UserForbid> res = userForbidService.page(page,Wrappers.lambdaQuery(UserForbid.class)
                    .eq(UserForbid::getForbidStatus,1));
            List<UserForbid> records = res.getRecords();
            if(records.isEmpty()){
                break;
            }
            for (UserForbid record : records) {
                if(record.getEndTime().isAfter(LocalDateTime.now())){
                    expireIds.add(record.getId());
                }else if(record.getEndTime().plusHours(12).isAfter(LocalDateTime.now())){ // 还有12小时过期
                    expireConsumer.add(record.getId());
                }
            }
        }
        for (Long expireId : expireIds) {
            checkExpire(expireId);
        }
        for (Long expireId : expireConsumer) {
            UserForbid userForbid = userForbidService.getById(expireId);
            if(userForbid == null || userForbid.getForbidStatus() == 2){
                return;
            }
            // 后者 - 前者 < 12小时
            long between = ChronoUnit.SECONDS.between(LocalDateTime.now(), userForbid.getEndTime());
            if(between > 0 && between < 60*60*12){
                CommonDelayDto dto = new CommonDelayDto();
                dto.setForbidId(expireId);
                dto.setType(2);
                amqpProducer.sendCommonDelayMq(dto,(int)between+5);
            }
        }
    }

    @Autowired
    private AmqpProducer amqpProducer;

    public void checkExpire(Long id){
        UserForbid userForbid = userForbidService.getById(id);
        if(userForbid == null || userForbid.getForbidStatus() == 2){
            return;
        }
        if(!userForbid.getEndTime().isAfter(LocalDateTime.now())){
            return;
        }
        this.unForbidByForbidId(id);

    }

    @Data
    public static class CheckForbid implements Serializable {
        // 是否已经被封禁
        private boolean forbid = false;
        private String traceId;
        private String message;

        public static CheckForbid noForbid(){
            return new CheckForbid();
        }

        public static CheckForbid forbid(String traceId){
            CheckForbid checkForbid = new CheckForbid();
            checkForbid.setForbid(true);
            checkForbid.setTraceId(traceId);
            return checkForbid;
        }
    }

}
