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

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
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.attendance.feign.RemoteAttendanceStrategyService;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.Dict;
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.enums.IssuedTypeEnum;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.Asserts;
import com.yida.data.common.service.CommonService;
import com.yida.data.user.dto.*;
import com.yida.data.user.mapper.EduFaceGroupUserMapper;
import com.yida.data.user.mapper.EduStudentApplyMapper;
import com.yida.data.user.mapper.EduStudentMapper;
import com.yida.data.user.mapper.EduUserDeviceMapper;
import com.yida.data.user.service.EduFaceGroupDeviceService;
import com.yida.data.user.service.EduFaceGroupStrategyService;
import com.yida.data.user.service.EduFaceGroupUserService;
import com.yida.data.user.service.EduStudentService;
import com.yida.data.user.service.EduUserDeptService;
import com.yida.data.user.vo.OutPageStudentVO;
import com.yida.data.user.vo.UserFacePageVO;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import javax.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 用户、人脸组关联信息 Service实现
 *
 * @author zhanghaijun
 * @date 2021-06-16 14:13:31
 */
@Slf4j
@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;

    private final EduFaceGroupStrategyService eduFaceGroupStrategyService;
    private final RemoteAttendanceStrategyService remoteAttendanceStrategyService;

    private final EduStudentMapper eduStudentMapper;
    private final EduStudentApplyMapper eduStudentApplyMapper;
    private final CommonService commonService;


    @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,
        Long campusId, Long sectionId, Long gradeId, Long classId) {
//        List<Long> classIds = null;
//        if (deptId != null) {
//            Long[] deptIds = new Long[]{deptId};
//            classId = eduUserDeptService.listClassByDept(Arrays.asList(deptIds));
//        }
        return baseMapper.listStudentNotImport(page, type, sex, keyword, schoolId, groupId, dormId, dormRoomId,
            campusId, sectionId, gradeId, classId);
    }

    @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(Integer type, Integer sex, String keyword, Long schoolId, Long groupId,
        Long dormId, Long dormRoomId,
        Long campusId, Long sectionId, Long gradeId, Long classId) {
        List<EduStudent> studentList = baseMapper
            .listStudentNotImport(type, sex, keyword, schoolId, groupId, dormId, dormRoomId,
                campusId, sectionId, gradeId, classId);
        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(EduStaff::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));
        List<EduFaceGroupUser> userList = list(
            Wrappers.lambdaQuery(new EduFaceGroupUser()).in(EduFaceGroupUser::getId, dto.getFaceIds()));
        // 删除和人脸组的关联关系
        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(EduFaceGroupUser::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);
            }
        }
        // 查询关联的设备信息
        List<EduFaceGroupDevice> list = eduFaceGroupDeviceService.list(
            Wrappers.lambdaQuery(new EduFaceGroupDevice()).eq(EduFaceGroupDevice::getFaceGroupId, dto.getFaceGroupId()));
        if (CollUtil.isEmpty(list)) {
            return;
        }

        if (CollUtil.isNotEmpty(alreadyIssued)) {
            // 删除对应的人员-策略关系
            EduFaceGroupStrategy eduFaceGroupStrategy = new EduFaceGroupStrategy();
            eduFaceGroupStrategy.setFaceGroupId(dto.getFaceGroupId());
            eduFaceGroupStrategy.setGroupDeviceList(list);
            eduFaceGroupStrategy.setGroupUserList(userList);
            remoteAttendanceStrategyService.unBindUserStrategy(eduFaceGroupStrategy);
//            // 移除对应的缓存
//            for (EduFaceGroupUser groupUser : userList) {
//                redisService.hdel(CachePrefixConstant.USER_ATTENDANCE_STRATEGY +
//                        groupUser.getUserId().toString() + groupUser.getUserType().toString(), String.valueOf(dto.getFaceGroupId()));
//            }
        }
    }

    @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(EduUserFace::getFaceGroupUserId).collect(Collectors.toList()))
            .set(EduFaceGroupUser::getStatus, EduFaceGroupUser.ISSUING));
        Dict dict = commonService.getDictByTypeAndValueOrLabel("apply_type", null, "食堂消费");
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        for (EduUserFace face : faceList) {
//            log.info("下发人脸信息：{}", face);
            face.setFaceGroupUserId(dto.getFaceGroupId());
            //添加学生IC卡号，是否是会员
            if (face.getUserType() == 0) {
//                EduStudent student = (EduStudent) redisService
//                    .hget(CachePrefixConstant.STUDENT_DATA, face.getUserId().toString());
//                if (ObjectUtil.isNull(student)) {
//                    student = eduStudentMapper.selectById(face.getUserId());
//                }
                EduStudent student = eduStudentMapper.selectById(face.getUserId());
                log.info("下发学生信息：{}", student);
                if (ObjectUtil.isNotNull(student)) {
                    face.setRfidCard(student.getStuCardNumber());
                }
                //查询会员信息
                if (Objects.isNull(dict)) {
                    throw new FebsException("当前学校暂不支持此功能");
                }
                // 查询是否是会员
                EduStudentApply studentApply = eduStudentApplyMapper
                    .getStudentApply(face.getUserId(), dict.getValue());
                if (ObjectUtil.isNotNull(studentApply)) {
                    face.setNotes(1);
                    face.setCardValidBegin(studentApply.getStartTime().format(fmt));
                    face.setCardValidEnd(studentApply.getEndTime().format(fmt));
                } else {
                    face.setNotes(0);
                }
            } else {
                face.setNotes(1);
                face.setCardValidBegin("2023-01-01 00:00:00");
                face.setCardValidEnd("2123-01-01 00:00:00");
            }
        }
        IssuedFaceDTO issuedFaceDTO = new IssuedFaceDTO();
        issuedFaceDTO.setUserFaceList(faceList);
        issuedFaceDTO.setDeviceList(deviceIds);
//        issuedFaceDTO.setType(0);
        issuedFaceDTO.setGroupId(dto.getFaceGroupId());
        // 判断是否有策略信息
        EduFaceGroupStrategy groupStrategy = eduFaceGroupStrategyService.getOne(Wrappers.lambdaQuery(new EduFaceGroupStrategy())
            .eq(EduFaceGroupStrategy::getFaceGroupId, dto.getFaceGroupId()));
        issuedFaceDTO.setGroupStrategy(groupStrategy);
        // 人脸组下发
        issuedFaceDTO.setIssuedTypeEnum(IssuedTypeEnum.FACE_GROUP);
        // 调用设备进行下发
        remoteAttendanceDeviceService.issuedFace(issuedFaceDTO);
    }

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