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

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yida.data.attendance.dto.AddLeaveRequestStrategyDTO;
import com.yida.data.attendance.dto.IssuedFaceDTO;
import com.yida.data.attendance.service.EduAttendanceDeviceGroupService;
import com.yida.data.attendance.service.EduAttendanceDeviceService;
import com.yida.data.attendance.service.EduAttendanceStrategyService;
import com.yida.data.attendance.service.EduUserStrategyService;
import com.yida.data.attendance.utils.MqttUtil;
import com.yida.data.common.core.entity.attendance.EduAttendanceDevice;
import com.yida.data.common.core.entity.attendance.EduUserStrategy;
import com.yida.data.common.core.entity.attendance.enums.DeviceStateEnum;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.constant.hq.HaiqingConstant;
import com.yida.data.common.core.entity.user.EduFaceGroupDevice;
import com.yida.data.common.core.entity.user.EduFaceGroupStrategy;
import com.yida.data.common.core.entity.user.EduFaceGroupStrategyPlanTime;
import com.yida.data.common.core.entity.user.EduFaceGroupStrategySpecialDate;
import com.yida.data.common.core.entity.user.EduFaceGroupStrategySpecialTime;
import com.yida.data.common.core.entity.user.EduFaceGroupUser;
import com.yida.data.common.core.entity.user.EduUserFace;
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.user.feign.RemoteUserFaceService;

import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * 设备策略service
 *
 * @author ZYJ
 * @date 2022/12/13
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EduAttendanceStrategyServiceImpl implements EduAttendanceStrategyService {

    private final EduUserStrategyService eduUserStrategyService;
    private final EduAttendanceDeviceService eduAttendanceDeviceService;
    private final EduAttendanceDeviceGroupService eduAttendanceDeviceGroupService;

    private final RemoteUserFaceService remoteUserFaceService;

    private final MqttUtil mqttUtil;
    private final RedisService redisService;

    @Override
    public void saveStrategyAndUser(EduFaceGroupStrategy eduFaceGroupStrategy) {
        // 设置策略
        JSONObject params = new JSONObject();
        params.set("operator", HaiqingConstant.ADD_ACCESS_STRATEGY);
        params.set("messageId", StrUtil.uuid().replace("-", ""));
        // 包装信息主体
        JSONObject info = JSONUtil.createObj()
                // 策略id使用人脸组id
                .set("strategyID", eduFaceGroupStrategy.getFaceGroupId())
                .set("startDate", eduFaceGroupStrategy.getStrategyStartDate().format(DateTimeFormatter.ofPattern("yyyy-MM" +
                        "-dd'T'HH:mm:ss")))
                .set("endDate", eduFaceGroupStrategy.getStrategyEndDate().format(DateTimeFormatter.ofPattern("yyyy-MM" +
                        "-dd'T'HH:mm:ss")));
        // 周一
        JSONArray monday = new JSONArray();
        if (CollUtil.isNotEmpty(eduFaceGroupStrategy.getMondayTimeList())) {
            for (EduFaceGroupStrategyPlanTime strategyPlanTime : eduFaceGroupStrategy.getMondayTimeList()) {
                monday.add(JSONUtil.createObj()
                        .set("startTime", strategyPlanTime.getPlanStartTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                        .set("endTime", strategyPlanTime.getPlanEndTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                );
            }
        }
        info.set("monday", monday);
        // 周二
        JSONArray tuesday = new JSONArray();
        if (CollUtil.isNotEmpty(eduFaceGroupStrategy.getTuesdayTimeList())) {
            for (EduFaceGroupStrategyPlanTime strategyPlanTime : eduFaceGroupStrategy.getTuesdayTimeList()) {
                tuesday.add(JSONUtil.createObj()
                        .set("startTime", strategyPlanTime.getPlanStartTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                        .set("endTime", strategyPlanTime.getPlanEndTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                );
            }
        }
        info.set("tuesday", tuesday);
        // 周三
        JSONArray wednesday = new JSONArray();
        if (CollUtil.isNotEmpty(eduFaceGroupStrategy.getWednesdayTimeList())) {
            for (EduFaceGroupStrategyPlanTime strategyPlanTime : eduFaceGroupStrategy.getWednesdayTimeList()) {
                wednesday.add(JSONUtil.createObj()
                        .set("startTime", strategyPlanTime.getPlanStartTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                        .set("endTime", strategyPlanTime.getPlanEndTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                );
            }
        }
        info.set("wednesday", wednesday);
        // 周四
        JSONArray thursday = new JSONArray();
        if (CollUtil.isNotEmpty(eduFaceGroupStrategy.getThursdayTimeList())) {
            for (EduFaceGroupStrategyPlanTime strategyPlanTime : eduFaceGroupStrategy.getThursdayTimeList()) {
                thursday.add(JSONUtil.createObj()
                        .set("startTime", strategyPlanTime.getPlanStartTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                        .set("endTime", strategyPlanTime.getPlanEndTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                );
            }
        }
        info.set("thursday", thursday);
        // 周五
        JSONArray friday = new JSONArray();
        if (CollUtil.isNotEmpty(eduFaceGroupStrategy.getFridayTimeList())) {
            for (EduFaceGroupStrategyPlanTime strategyPlanTime : eduFaceGroupStrategy.getFridayTimeList()) {
                friday.add(JSONUtil.createObj()
                        .set("startTime", strategyPlanTime.getPlanStartTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                        .set("endTime", strategyPlanTime.getPlanEndTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                );
            }
        }
        info.set("friday", friday);
        // 周六
        JSONArray saturday = new JSONArray();
        if (CollUtil.isNotEmpty(eduFaceGroupStrategy.getSaturdayTimeList())) {
            for (EduFaceGroupStrategyPlanTime strategyPlanTime : eduFaceGroupStrategy.getSaturdayTimeList()) {
                saturday.add(JSONUtil.createObj()
                        .set("startTime", strategyPlanTime.getPlanStartTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                        .set("endTime", strategyPlanTime.getPlanEndTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                );
            }
        }
        info.set("saturday", saturday);
        // 周天
        JSONArray sunday = new JSONArray();
        if (CollUtil.isNotEmpty(eduFaceGroupStrategy.getSundayTimeList())) {
            for (EduFaceGroupStrategyPlanTime strategyPlanTime : eduFaceGroupStrategy.getSundayTimeList()) {
                sunday.add(JSONUtil.createObj()
                        .set("startTime", strategyPlanTime.getPlanStartTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                        .set("endTime", strategyPlanTime.getPlanEndTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                );
            }
        }
        info.set("sunday", sunday);
        // 处理特殊日期
        JSONArray holidayInfo = JSONUtil.createArray();
        if (CollUtil.isNotEmpty(eduFaceGroupStrategy.getSpecialDateList())) {
            for (EduFaceGroupStrategySpecialDate specialDate : eduFaceGroupStrategy.getSpecialDateList()) {
                JSONObject jsonObject = JSONUtil.createObj()
                        .set("holidayStartDate", specialDate.getSpecialStartDate()
                                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + "T00:00:00")
                        .set("holidayEndDate", specialDate.getSpecialEndDate()
                                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + "T23:59:59");
                // 处理时间
                JSONArray holidayPeriod = JSONUtil.createArray();
                for (EduFaceGroupStrategySpecialTime specialTime : specialDate.getSpecialTimeList()) {
                    holidayPeriod.add(JSONUtil.createObj()
                            .set("startTime", specialTime.getSpecialStartTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                            .set("endTime", specialTime.getSpecialEndTime().format(DateTimeFormatter.ofPattern("HH:mm:ss")))
                    );
                }
                jsonObject.set("holidayPeriod", holidayPeriod);
                holidayInfo.add(jsonObject);
            }
        }
        info.set("holidayInfo", holidayInfo);
        // 信息主体
        params.set("info", info);
        // 处理设备集合
        List<EduAttendanceDevice> deviceList = checkGroupDevice(eduFaceGroupStrategy);
        List<EduFaceGroupUser> userList = eduFaceGroupStrategy.getGroupUserList();

        for (EduAttendanceDevice device : deviceList) {
            log.info("推送的策略信息=================sn: {}, params: {}", device.getSn(), params);
            // 添加策略消息
            mqttUtil.publish(params.toString(), "mqtt/face/" + device.getSn());

            if (CollUtil.isNotEmpty(userList)) {
                JSONObject userParams = JSONUtil.createObj();
                // 设置人员绑定策略
                userParams.set("operator", HaiqingConstant.PERSONS_BIND_STRATEGY)
                        .set("messageId", StrUtil.uuid().replace("-", ""));
                JSONArray personsInfo = JSONUtil.createArray();
                for (EduFaceGroupUser groupUser : userList) {
                    String customId = groupUser.getUserId().toString() + groupUser.getUserType().toString();
                    JSONObject singleObject = JSONUtil.createObj()
                            // 用户id+用户类型
                            .set("customId", customId);
                    Map<Object, Object> map = redisService.hmget(CachePrefixConstant.USER_ATTENDANCE_STRATEGY
                            + device.getSn() + "-" + customId);
                    // 设置用户信息
                    JSONArray array = JSONUtil.createArray();
                    map.forEach((k, v) -> array.add(k));
                    singleObject.set("strategyID", array);

                    personsInfo.add(singleObject);
                }
                // 人员绑定通行策略
                userParams.set("info", JSONUtil.createObj().set("personsInfo", personsInfo));
                log.info("推送的人员绑定信息=================sn: {}, params: {}", device.getSn(), userParams);
                mqttUtil.publish(userParams.toString(), "mqtt/face/" + device.getSn());
            }
        }
    }

    /**
     * 处理设备信息
     *
     * @param eduFaceGroupStrategy 人脸组-策略信息
     * @return java.util.List<com.yida.data.common.core.entity.attendance.EduAttendanceDevice>
     * @author ZYJ
     * @date 2022/12/22 16:58
     */
    public List<EduAttendanceDevice> checkGroupDevice(EduFaceGroupStrategy eduFaceGroupStrategy) {
        // 处理设备集合
        List<EduFaceGroupDevice> deviceAndGroup = eduFaceGroupStrategy.getGroupDeviceList();
        List<EduAttendanceDevice> deviceList = new ArrayList<>();
        // 处理设备
        List<Long> deviceIds = deviceAndGroup.stream().filter(x -> x.getType() == 0).map(EduFaceGroupDevice::getDeviceId)
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(deviceIds)) {
            List<EduAttendanceDevice> devices = eduAttendanceDeviceService.list(
                    Wrappers.lambdaQuery(new EduAttendanceDevice()).in(EduAttendanceDevice::getId, deviceIds));
            if (CollUtil.isNotEmpty(devices)) {
                deviceList.addAll(devices);
            }
        }
        // 处理设备组
        List<Long> deviceGroupIds = deviceAndGroup.stream().filter(x -> x.getType() == 1).map(EduFaceGroupDevice::getDeviceId)
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(deviceGroupIds)) {
            List<EduAttendanceDevice> groupDevices = eduAttendanceDeviceGroupService.listDeviceByGroup(deviceGroupIds);
            if (CollUtil.isNotEmpty(groupDevices)) {
                deviceList.addAll(groupDevices);
            }
        }
        if (CollUtil.isEmpty(deviceList)) {
            log.info("当前人脸组策略没有对应的设备信息: {}", eduFaceGroupStrategy.getFaceGroupId());
            return new ArrayList<>();
        }
        return deviceList;
    }

    @Override
    public void deleteStrategy(EduFaceGroupStrategy eduFaceGroupStrategy) {
        // 处理设备集合
        List<EduAttendanceDevice> deviceList = checkGroupDevice(eduFaceGroupStrategy);

        // 设置删除策略信息
        JSONObject params = JSONUtil.createObj()
                .set("operator", HaiqingConstant.DEL_ACCESS_STRATEGY)
                .set("messageId", StrUtil.uuid().replace("-", ""))
                .set("info", JSONUtil.createObj()
                        .set("strategyID", JSONUtil.createArray().set(eduFaceGroupStrategy.getFaceGroupId())));

        for (EduAttendanceDevice device : deviceList) {
            log.info("推送的删除策略消息=================sn: {}, params: {}", device.getSn(), params);
            // 删除策略消息
            mqttUtil.publish(params.toString(), "mqtt/face/" + device.getSn());
        }
    }

    @Override
    public void bindUserStrategy(EduFaceGroupStrategy eduFaceGroupStrategy) {
        // 处理设备集合
        List<EduAttendanceDevice> deviceList = checkGroupDevice(eduFaceGroupStrategy);

        List<EduFaceGroupUser> userList = eduFaceGroupStrategy.getGroupUserList();
        if (CollUtil.isNotEmpty(userList)) {

            for (EduAttendanceDevice device : deviceList) {
                JSONObject userParams = JSONUtil.createObj();
                // 设置人员绑定策略
                userParams.set("operator", HaiqingConstant.PERSONS_BIND_STRATEGY)
                        .set("messageId", StrUtil.uuid().replace("-", ""));
                JSONArray personsInfo = JSONUtil.createArray();
                // 封装每个设备的用户策略信息
                for (EduFaceGroupUser groupUser : userList) {
                    String customId = groupUser.getUserId().toString() + groupUser.getUserType().toString();
                    JSONObject singleObject = JSONUtil.createObj()
                            // 用户id+用户类型
                            .set("customId", customId);
                    Map<Object, Object> map = redisService.hmget(CachePrefixConstant.USER_ATTENDANCE_STRATEGY +
                            device.getSn() + "-" + customId);
                    // 设置用户信息
                    JSONArray array = JSONUtil.createArray();
                    map.forEach((k, v) -> array.add(k));
                    singleObject.set("strategyID", array);

                    personsInfo.add(singleObject);
                }
                userParams.set("info", JSONUtil.createObj().set("personsInfo", personsInfo));
                log.info("推送的解绑策略消息=================sn: {}, params: {}", device.getSn(), userParams);
                // 绑定策略消息
                mqttUtil.publish(userParams.toString(), "mqtt/face/" + device.getSn());
            }
        }
    }

    /**
     * 解绑对应的人员-策略信息
     *
     * @param eduFaceGroupStrategy 策略信息
     * @author ZYJ
     * @date 2022/12/26 10:19
     */
    @Override
    public void unBindUserStrategy(EduFaceGroupStrategy eduFaceGroupStrategy) {
        // 处理设备集合
        List<EduAttendanceDevice> deviceList = checkGroupDevice(eduFaceGroupStrategy);

        List<EduFaceGroupUser> userList = eduFaceGroupStrategy.getGroupUserList();
        if (CollUtil.isNotEmpty(userList)) {

            for (EduAttendanceDevice device : deviceList) {
                JSONObject userParams = JSONUtil.createObj();
                // 设置人员绑定策略
                userParams.set("operator", HaiqingConstant.PERSONS_UNBIND_STRATEGY)
                        .set("messageId", StrUtil.uuid().replace("-", ""));
                JSONArray personsInfo = JSONUtil.createArray();
                for (EduFaceGroupUser groupUser : userList) {
                    String customId = groupUser.getUserId().toString() + groupUser.getUserType().toString();
                    JSONObject singleObject = JSONUtil.createObj()
                            // 用户id+用户类型
                            .set("customId", customId);
                    // 设置用户信息
                    JSONArray array = JSONUtil.createArray().set(eduFaceGroupStrategy.getFaceGroupId());
                    singleObject.set("strategyID", array);
                    personsInfo.add(singleObject);
                    // 移除对应的缓存
                    redisService.hdel(CachePrefixConstant.USER_ATTENDANCE_STRATEGY +
                            device.getSn() + "-" + customId, String.valueOf(eduFaceGroupStrategy.getFaceGroupId()));
                }
                userParams.set("info", JSONUtil.createObj().set("personsInfo", personsInfo));
                log.info("推送的解绑策略消息=================sn: {}, params: {}", device.getSn(), userParams);
                // 解绑策略消息
                mqttUtil.publish(userParams.toString(), "mqtt/face/" + device.getSn());
            }
        }
    }

    @Override
    public void deleteAndSaveStrategy(EduFaceGroupStrategy eduFaceGroupStrategy) {
        unBindUserStrategy(eduFaceGroupStrategy);
        deleteStrategy(eduFaceGroupStrategy);
        // 添加缓存信息
        for (EduFaceGroupDevice groupDevice : eduFaceGroupStrategy.getGroupDeviceList()) {
            EduAttendanceDevice device = eduAttendanceDeviceService.getById(groupDevice.getDeviceId());
            for (EduFaceGroupUser groupUser : eduFaceGroupStrategy.getGroupUserList()) {
                String customId = groupUser.getUserId().toString() + groupUser.getUserType().toString();
                redisService.hset(CachePrefixConstant.USER_ATTENDANCE_STRATEGY +
                        device.getSn() + "-" + customId, String.valueOf(eduFaceGroupStrategy.getFaceGroupId()), 1);
            }
        }
        saveStrategyAndUser(eduFaceGroupStrategy);
    }

    @Override
    public void addLeaveRequestStrategy(AddLeaveRequestStrategyDTO dto) {
        // 查询学校校门的设备
        List<EduAttendanceDevice> deviceList = eduAttendanceDeviceService.list(Wrappers.lambdaQuery(new EduAttendanceDevice())
                .eq(EduAttendanceDevice::getSchoolId, dto.getSchoolId())
                .eq(EduAttendanceDevice::getDeviceType, DeviceType.HAIQING.getValue())
                .eq(EduAttendanceDevice::getState, DeviceStateEnum.ONLINE_STATUS.getStatus())
                // 校门类型
                .eq(EduAttendanceDevice::getType, 0)
        );
        if (CollUtil.isEmpty(deviceList)) {
            return;
        }
        // 查询人脸信息
        EduUserFace eduUserFace = remoteUserFaceService.getFaceByUser(dto.getUserId(), dto.getRequestType() == 1 ? 0 : 1).getData();
        if (Objects.isNull(eduUserFace)) {
            throw new FebsException("审核失败！请上传人脸信息后重新审核");
        }
        // 添加策略
        JSONObject params = new JSONObject();
        params.set("operator", HaiqingConstant.ADD_ACCESS_STRATEGY);
        params.set("messageId", StrUtil.uuid().replace("-", ""));
        // 包装信息主体
        JSONObject info = JSONUtil.createObj()
                // 策略id使用人脸组id
                .set("strategyID", dto.getStrategyId())
                .set("startDate", dto.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM" +
                        "-dd'T'HH:mm:ss")))
                .set("endDate", dto.getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM" +
                        "-dd'T'HH:mm:ss")));
        info.set("monday", JSONUtil.createArray());
        info.set("tuesday", JSONUtil.createArray());
        info.set("wednesday", JSONUtil.createArray());
        info.set("thursday", JSONUtil.createArray());
        info.set("friday", JSONUtil.createArray());
        info.set("saturday", JSONUtil.createArray());
        info.set("sunday", JSONUtil.createArray());
        info.set("holidayInfo", JSONUtil.createArray());
        // 信息主体
        params.set("info", info);
        for (EduAttendanceDevice device : deviceList) {
            log.info("推送的策略信息=================sn: {}, params: {}", device.getSn(), params);
            // 添加策略消息
            mqttUtil.publish(params.toString(), "mqtt/face/" + device.getSn());
        }
        // 保存人员请假策略信息
        eduUserStrategyService.saveOrUpdate(EduUserStrategy.builder()
                .strategyId(dto.getStrategyId())
                .userId(dto.getUserId())
                .userType(dto.getRequestType() == 0 ? 1 : 0)
                .startTime(dto.getStartTime())
                .endTime(dto.getEndTime())
                .deptId(dto.getSchoolId())
                .build()
        );
        // 生成人脸下发信息
        IssuedFaceDTO issuedFaceDTO = new IssuedFaceDTO();
        issuedFaceDTO.setUserFaceList(Collections.singletonList(eduUserFace));
        issuedFaceDTO.setDeviceList(deviceList.stream().map(EduAttendanceDevice::getId).collect(Collectors.toList()));
        issuedFaceDTO.setGroupId(dto.getStrategyId());
        EduFaceGroupStrategy groupStrategy = new EduFaceGroupStrategy();
        groupStrategy.setFaceGroupId(dto.getStrategyId());
        issuedFaceDTO.setGroupStrategy(groupStrategy);
        // 请假下发
        issuedFaceDTO.setIssuedTypeEnum(IssuedTypeEnum.LEAVE_REQUEST);
        // 下发人脸、绑定策略和人员关系
        eduAttendanceDeviceService.issuedFace(issuedFaceDTO);
    }
}
