package com.yida.data.user.service.impl;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yida.data.attendance.dto.IssuedFaceDTO;
import com.yida.data.attendance.dto.RemoveFaceDTO;
import com.yida.data.attendance.feign.RemoteAttendanceDeviceService;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.attendance.EduAttendanceDevice;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.constant.LockPrefixConstant;
import com.yida.data.common.core.entity.user.*;
import com.yida.data.common.core.enums.DeviceType;
import com.yida.data.common.core.utils.Asserts;
import com.yida.data.user.dto.*;
import com.yida.data.user.mapper.EduFaceGroupUserMapper;
import com.yida.data.user.mapper.EduUserDeviceMapper;
import com.yida.data.user.service.EduFaceGroupDeviceService;
import com.yida.data.user.service.EduFaceGroupUserService;
import com.yida.data.user.service.EduUserDeptService;
import com.yida.data.user.vo.UserFacePageVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户、人脸组关联信息 Service实现
 *
 * @author zhanghaijun
 * @date 2021-06-16 14:13:31
 */
@Service
@RequiredArgsConstructor
@Transactional
public class EduFaceGroupUserServiceImpl extends ServiceImpl
    <EduFaceGroupUserMapper, EduFaceGroupUser> implements EduFaceGroupUserService {

    private final RedisService redisService;
    private final EduUserDeviceMapper eduUserDeviceMapper;
    private final EduFaceGroupDeviceService eduFaceGroupDeviceService;
    private final RemoteAttendanceDeviceService remoteAttendanceDeviceService;
    private final EduUserDeptService eduUserDeptService;

    @Override
    public IPage<UserFacePageVO> listUserFacePage(FaceGroupUserPageDTO dto) {
        return baseMapper.listUserFacePage(dto.toPage(), dto);
    }

    @Override
    public IPage<EduStudent> listStudentNotImport(Page page, Long deptId, Integer type, Integer sex,
        String keyword, Long schoolId, Long groupId, Long dormId, Long dormRoomId) {
        List<Long> classId = null;
        if (deptId != null) {
            Long[] deptIds = new Long[]{deptId};
            classId = this.eduUserDeptService.listClassByDept(Arrays.asList(deptIds));
        }
        return baseMapper.listStudentNotImport(page, classId, type, sex, keyword, schoolId, groupId, dormId, dormRoomId);
    }

    @Override
    public IPage<EduStaff> listStaffNotImport(Page page, Integer sex, String keyword, Long schoolId,
        Long groupId) {
        return baseMapper.listStaffNotImport(page, sex, keyword, schoolId, groupId);
    }

    @Override
    public void saveAllStudent(List<Long> classId, Integer type, Integer sex, String keyword, Long schoolId, Long groupId,
                               Long dormId, Long dormRoomId) {
        List<EduStudent> studentList = baseMapper.listStudentNotImport(classId, type, sex, keyword, schoolId, groupId, dormId, dormRoomId);
        if (CollUtil.isNotEmpty(studentList)) {
            List<EduFaceGroupUser> saveUser = new ArrayList<>();
            for (Long userId : studentList.stream().map(EduStudent::getId).collect(Collectors.toList())) {
                EduFaceGroupUser eduFaceGroupUser = new EduFaceGroupUser();
                eduFaceGroupUser.setUserId(userId);
                eduFaceGroupUser.setUserType(0);
                eduFaceGroupUser.setStatus(0);
                eduFaceGroupUser.setFaceGroupId(groupId);
                saveUser.add(eduFaceGroupUser);
            }
            saveBatch(saveUser);
        }
    }

    @Override
    public void saveAllStaff(Integer sex, String keyword, Long schoolId, Long groupId) {
        List<EduStaff> staffList = baseMapper.listStaffNotImport(sex, keyword, schoolId, groupId);
        if (CollUtil.isNotEmpty(staffList)) {
            List<EduFaceGroupUser> saveUser = new ArrayList<>();
            for (Long userId : staffList.stream().map(x -> x.getId()).collect(Collectors.toList())) {
                EduFaceGroupUser eduFaceGroupUser = new EduFaceGroupUser();
                eduFaceGroupUser.setUserId(userId);
                eduFaceGroupUser.setUserType(1);
                eduFaceGroupUser.setStatus(0);
                eduFaceGroupUser.setFaceGroupId(groupId);
                saveUser.add(eduFaceGroupUser);
            }
            saveBatch(saveUser);
        }
    }

    @Override
    public void saveFaceGroupUser(SaveFaceGroupUserDTO dto, CurrentUser currentUser) {
        List<Long> userIds = CollUtil.isEmpty(dto.getUserId()) ? new ArrayList<>() : dto.getUserId();
        List<EduFaceGroupUser> saveUser = new ArrayList<>();
        for (Long userId : userIds) {
            EduFaceGroupUser eduFaceGroupUser = new EduFaceGroupUser();
            eduFaceGroupUser.setUserId(userId);
            eduFaceGroupUser.setUserType(dto.getType());
            eduFaceGroupUser.setStatus(0);
            eduFaceGroupUser.setFaceGroupId(dto.getFaceGroupId());
            saveUser.add(eduFaceGroupUser);
        }
        saveBatch(saveUser);
    }

    @Override
    public void delUserBatch(DelFaceGroupUserDTO dto) {
        // 已经下发的人
        List<EduFaceGroupUser> alreadyIssued = list(
            Wrappers.lambdaQuery(new EduFaceGroupUser()).in(EduFaceGroupUser::getId, dto.getFaceIds())
                .eq(EduFaceGroupUser::getStatus, 1));
        // 删除和人脸组的关联关系
        removeByIds(dto.getFaceIds());
        // 已下发的人要删除下发记录
        if (CollUtil.isNotEmpty(alreadyIssued)) {
            // 该人脸组的设备
            List<Long> deviceList = eduFaceGroupDeviceService.listDeviceByFaceGroup(dto.getFaceGroupId());
            Map<Integer, List<EduFaceGroupUser>> issuedMap = alreadyIssued.stream()
                .collect(Collectors.groupingBy(EduFaceGroupUser::getUserType));
            // 查询需要从设备上删除的人(仅被该人脸组下发的人脸)
            List<String> deviceFactoryUserId = CollUtil.isNotEmpty(deviceList)
                ? eduUserDeviceMapper.listUserDevicesNotInList(alreadyIssued, deviceList, DeviceType.HAIQING.getValue())
                : null;
            // 删除用户在此人脸组的下发记录
            for (Map.Entry<Integer, List<EduFaceGroupUser>> entry : issuedMap.entrySet()) {
                Integer userType = entry.getKey();
                List<Long> userIds = entry.getValue().stream().map(x -> x.getUserId()).collect(Collectors.toList());
                LambdaQueryWrapper<EduUserDevice> condition = Wrappers.lambdaQuery(new EduUserDevice())
                    .in(EduUserDevice::getUserId, userIds)
                    .eq(EduUserDevice::getUserType, userType);
                if (dto.getFaceGroupId() != null) {
                    condition.eq(EduUserDevice::getFaceGroupId, dto.getFaceGroupId());
                }
                eduUserDeviceMapper.delete(condition);
            }
            // 删除设备上的人脸
            if (CollUtil.isNotEmpty(deviceFactoryUserId)) {
                RemoveFaceDTO removeFaceDTO = new RemoveFaceDTO();
                removeFaceDTO.setDeviceFactoryUserId(deviceFactoryUserId);
                removeFaceDTO.setDeviceList(deviceList);
                remoteAttendanceDeviceService.removeFace(removeFaceDTO);
            }
        }
    }

    @Override
    public void issueBatch(BatchIssueDTO dto, CurrentUser currentUser) {
        // 人脸组关联的设备
        List<Long> deviceIds = eduFaceGroupDeviceService.listDeviceByFaceGroup(dto.getFaceGroupId());
        List<EduAttendanceDevice> deviceList = remoteAttendanceDeviceService.listDeviceById(deviceIds.toArray(new Long[0]))
            .getData();
        Asserts.isTrue(CollUtil.isNotEmpty(deviceList), "该人脸组暂未绑定设备!");
        // 该人脸组的设备是否有正在下发操作
        Asserts.isFalse(redisService.hasKey(LockPrefixConstant.ISSUE_FACE_LOCK + dto.getFaceGroupId()), "该人脸组正在进行下发操作，请稍后重试!");
        boolean flag = true;
        StringBuilder msg = new StringBuilder();
        redisService.lock(LockPrefixConstant.ISSUE_FACE_LOCK + dto.getFaceGroupId());
        for (EduAttendanceDevice device : deviceList) {
            // 判断该设备是否仍有数据未下发完成
            if (redisService.hasKey(CachePrefixConstant.HQ_EDIT_BATCH + device.getSn())) {
                flag = false;
                msg.append(device.getName())
                    .append(device.getZoneScope() == 0 ? "进门" : "出门")
                    .append("人脸机")
                    .append("正在下发，请稍后重试");
                break;
            }
            // 设备是否在线
            if (device.getState() == 1) {
                flag = false;
                msg.append(device.getName())
                    .append(device.getZoneScope() == 0 ? "进门" : "出门")
                    .append("人脸机")
                    .append("不在线，请稍后重试");
                break;
            }
        }
        redisService.unlock(LockPrefixConstant.ISSUE_FACE_LOCK + dto.getFaceGroupId());
        Asserts.isTrue(flag, msg.toString());
        // 查询人脸组中全部未下发的人脸
        List<EduUserFace> faceList = dto.getType() == 1
            ? baseMapper.listUserFace(dto.getIds())
            : baseMapper.listUserFaceByGroup(dto.getFaceGroupId());
        Asserts.isTrue(CollUtil.isNotEmpty(faceList), "请上传人脸！");
        // 更新下发状态
        update(Wrappers.lambdaUpdate(new EduFaceGroupUser())
            .in(EduFaceGroupUser::getId, faceList.stream().map(x -> x.getFaceGroupUserId()).collect(Collectors.toList()))
            .set(EduFaceGroupUser::getStatus, EduFaceGroupUser.ISSUING));
        for (EduUserFace face : faceList) {
            face.setFaceGroupUserId(dto.getFaceGroupId());
        }
        IssuedFaceDTO issuedFaceDTO = new IssuedFaceDTO();
        issuedFaceDTO.setUserFaceList(faceList);
        issuedFaceDTO.setDeviceList(deviceIds);
        issuedFaceDTO.setType(0);
        issuedFaceDTO.setGroupId(dto.getFaceGroupId());
        // 调用设备进行下发
        remoteAttendanceDeviceService.issuedFace(issuedFaceDTO);
    }

    @Override
    public void updateStatus(UpdateFaceGroupUserStatusDTO dto) {
        baseMapper.updateStatus(dto);
    }
}
