package jnpf.personnels.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jnpf.base.entity.SuperBaseEntity;
import jnpf.model.personnels.dto.black.FtbPersonnelsBlackListDTO;
import jnpf.model.personnels.dto.black.FtbPersonnelsBlackUpdateDTO;
import jnpf.model.personnels.dto.black.FtbPersonnelsBlacklistAddDTO;
import jnpf.model.personnels.po.FtbPersonnelsBlacklist;
import jnpf.model.personnels.po.FtbPersonnelsBlacklistHistory;
import jnpf.model.personnels.vo.black.BlackTermEnum;
import jnpf.model.personnels.vo.black.FtbPersonnelsBlackListVO;
import jnpf.permission.V2UserApi;
import jnpf.personnels.mapper.FtbPersonnelsBlacklistMapper;
import jnpf.personnels.service.FtbPersonnelsBlacklistHistoryService;
import jnpf.personnels.service.FtbPersonnelsBlacklistService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 黑名单 服务实现类
 * </p>
 *
 * @author wcx
 * @since 2024-05-08
 */
@Service
public class FtbPersonnelsBlacklistServiceImpl extends ServiceImpl<FtbPersonnelsBlacklistMapper, FtbPersonnelsBlacklist> implements FtbPersonnelsBlacklistService {

    @Resource
    private FtbPersonnelsBlacklistHistoryService ftbPersonnelsBlacklistHistoryService;

    @Autowired
    private V2UserApi v2UserApi;

    @Override
    public void addBlacklist(FtbPersonnelsBlacklistAddDTO ftbPersonnelsBlacklistAddDTO) {
        LambdaQueryWrapper<FtbPersonnelsBlacklist> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsBlacklist::getUserId, ftbPersonnelsBlacklistAddDTO.getUserId());
        FtbPersonnelsBlacklist ftbPersonnelsBlacklist = baseMapper.selectOne(queryWrapper);
        if (Objects.nonNull(ftbPersonnelsBlacklist)) {
            doBlacklistVerification(ftbPersonnelsBlacklist.getType(), ftbPersonnelsBlacklist.getCreatorTime());
        }
        FtbPersonnelsBlacklist result = ftbPersonnelsBlacklistAddDTO.convertFtbPersonnelsBlacklist(ftbPersonnelsBlacklistAddDTO);
        save(result);
    }

    @Override
    public Boolean hasItBeenBlacklisted(String phone) {
        LambdaQueryWrapper<FtbPersonnelsBlacklist> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsBlacklist::getPhone, phone);
        FtbPersonnelsBlacklist ftbPersonnelsBlacklist = baseMapper.selectOne(queryWrapper);
        if (Objects.nonNull(ftbPersonnelsBlacklist)) {
            try {
                doBlacklistVerification(ftbPersonnelsBlacklist.getType(), ftbPersonnelsBlacklist.getCreatorTime());
            } catch (RuntimeException e) {
                return true;
            }
        }
        return false;
    }

    @Override
    @Transactional
    public Page<FtbPersonnelsBlackListVO> blacklist(Page<FtbPersonnelsBlackListVO> page, FtbPersonnelsBlackListDTO dto) {
        // 校验黑名单失效，然后移入历史黑名单中
        verificationBlacklistInvalid();
        page = baseMapper.blacklist(page, dto);
        page.getRecords().forEach(item -> {
            item.setExpirationTime(item.getType().calculateFailureTime(item.getCreateTime()));
        });
        return page;
    }

    @Override
    public void editBlacklist(FtbPersonnelsBlackUpdateDTO fdto) {
        LambdaUpdateWrapper<FtbPersonnelsBlacklist> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(FtbPersonnelsBlacklist::getId, fdto.getId())
                .set(FtbPersonnelsBlacklist::getBlackTypeId, fdto.getBlackTypeId())
                .set(StrUtil.isNotBlank(fdto.getReason()), FtbPersonnelsBlacklist::getReason, fdto.getReason())
                .set(FtbPersonnelsBlacklist::getType, fdto.getType());
        baseMapper.update(new FtbPersonnelsBlacklist(), updateWrapper);
    }

    @Override
    @Transactional
    public void removeBlacklist(String id) {
        FtbPersonnelsBlacklist ftbPersonnelsBlacklist = baseMapper.selectById(id);
        FtbPersonnelsBlacklistHistory ftbPersonnelsHistory = FtbPersonnelsBlacklistHistory.convert(ftbPersonnelsBlacklist);
        ftbPersonnelsBlacklistHistoryService.save(ftbPersonnelsHistory);
        baseMapper.deleteById(id);
    }

    @Override
    public List<FtbPersonnelsBlackListVO.BlackTermEnumVO> getBlacklist() {
        return Arrays.stream(BlackTermEnum.values()).map(item -> {
            FtbPersonnelsBlackListVO.BlackTermEnumVO blackTermEnumVO = new FtbPersonnelsBlackListVO.BlackTermEnumVO();
            blackTermEnumVO.setCode(item.getCode());
            blackTermEnumVO.setName(item.getName());
            return blackTermEnumVO;
        }).collect(Collectors.toList());
    }

    private void verificationBlacklistInvalid() {
        LambdaQueryWrapper<FtbPersonnelsBlacklist> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsBlacklist::getEnableMark, 0);
        List<FtbPersonnelsBlacklist> ftbPersonnelsBlacklists = baseMapper.selectList(queryWrapper);
        Predicate<FtbPersonnelsBlacklist> predicate = ftbPersonnelsBlacklist -> {
            BlackTermEnum blackTermEnum = BlackTermEnum.getByCode(ftbPersonnelsBlacklist.getType());
            Date calculateFailureTime = blackTermEnum.calculateFailureTime(ftbPersonnelsBlacklist.getCreatorTime());
            return calculateFailureTime != null && calculateFailureTime.getTime() < System.currentTimeMillis();
        };
        // 移入历史黑名单的数据
        List<FtbPersonnelsBlacklistHistory> ftbPersonnelsBlacklistHistories = ftbPersonnelsBlacklists.stream()
                .filter(predicate).map(FtbPersonnelsBlacklistHistory::convert).peek(a -> a.setStatus(0)).collect(Collectors.toList());
        // 原有黑名单失效的删除
        List<String> blackListIds = ftbPersonnelsBlacklists.stream()
                .filter(predicate).map(SuperBaseEntity.SuperIBaseEntity::getId).collect(Collectors.toList());
        ftbPersonnelsBlacklistHistoryService.saveBatch(ftbPersonnelsBlacklistHistories);
        if (!CollectionUtils.isEmpty(blackListIds)) {
            baseMapper.deleteBatchIds(blackListIds);
        }
    }

    private void doBlacklistVerification(Integer type, Date startDate) {
        BlackTermEnum blackTermEnum = BlackTermEnum.getByCode(type);
        Date calculateFailureTime = blackTermEnum.calculateFailureTime(startDate);
        // 永久拉黑或者失效时间未过期
        if (calculateFailureTime == null || calculateFailureTime.getTime() > System.currentTimeMillis()) {
            throw new RuntimeException("该用户已存在黑名单中！");
        }
    }

}
