package com.zhongshu.card.server.core.service.devices.permiss;

import com.github.microservice.models.gateDoor.use.GateDoorUseParam;
import com.github.microservice.net.ResultContent;
import com.zhongshu.card.client.model.devices.permiss.PermissSettingListSearch;
import com.zhongshu.card.client.model.devices.permiss.TimeSlotModel;
import com.zhongshu.card.client.model.devices.permiss.TimeSlotWeekModel;
import com.zhongshu.card.client.model.devices.userCache.UserCacheModel;
import com.zhongshu.card.client.type.DataState;
import com.zhongshu.card.client.type.UserState;
import com.zhongshu.card.client.type.device.TimeSlotType;
import com.zhongshu.card.client.type.device.WeekDayType;
import com.zhongshu.card.client.utils.DateUtils;
import com.zhongshu.card.server.core.dao.devices.*;
import com.zhongshu.card.server.core.dao.org.OrganizationUserDao;
import com.zhongshu.card.server.core.dao.org.UserCountDao;
import com.zhongshu.card.server.core.dao.org.UserGroupToUserDao;
import com.zhongshu.card.server.core.domain.devices.DeviceInfo;
import com.zhongshu.card.server.core.domain.devices.permiss.DevicePermiss;
import com.zhongshu.card.server.core.domain.devices.permiss.PermissTimeSlot;
import com.zhongshu.card.server.core.domain.org.UserAccount;
import com.zhongshu.card.server.core.service.org.OrganizationUserServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

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

/**
 * 验证用户是否可以使用设备
 *
 * @author TRX
 * @date 2024/12/24
 */
@Slf4j
@Service
public class DevicePermissVerifyService {

    @Autowired
    private DevicePermissDao devicePermissDao;

    @Autowired
    private UserCountDao userCountDao;

    @Autowired
    private OrganizationUserDao organizationUserDao;

    @Autowired
    private DeviceInfoDao deviceInfoDao;

    @Autowired
    private PermissSettingListDao permissSettingListDao;

    @Autowired
    private PermissTimeSlotDao permissTimeSlotDao;

    @Autowired
    private DeviceGroupToDeviceDao deviceGroupToDeviceDao;

    @Autowired
    private OrganizationUserServiceImpl organizationUserService;

    @Autowired
    private UserGroupToUserDao userGroupToUserDao;

    @Autowired
    private UserPermissDataCacheService userPermissDataCacheService;

    /**
     * 验证用户是否有设备的使用权限
     *
     * @param userId
     * @param deviceId
     * @return
     */
    public ResultContent<String> verifyDevice(String userId, String deviceId, GateDoorUseParam deviceUserParam) {
        if (StringUtils.isEmpty(userId)) {
            return ResultContent.buildFail("未包含用户信息");
        }
        deviceUserParam.setUserId(userId);
        deviceUserParam.setDeviceId(deviceId);

        StopWatch stopWatch = new StopWatch();
        stopWatch.start("用户信息");
        String msg = "";

        // 验证用户基础信息
        UserAccount userAccount = userCountDao.findTopByUserId(userId);
        if (ObjectUtils.isEmpty(userAccount)) {
            return ResultContent.buildFail("用户不存在");
        }
        msg = userAccount.getName();
        if (userAccount.getState() != UserState.Normal) {
            return ResultContent.buildFail("用户不可用");
        }

        stopWatch.stop();

        stopWatch.start("查询设备信息");
        // 验证设备
        DeviceInfo deviceInfo = deviceInfoDao.findTopByDeviceId(deviceId);
        // 验证手动管理的设备权限
        stopWatch.stop();

        if (ObjectUtils.isEmpty(deviceInfo)) {
            return ResultContent.buildFail("设备不存在");
        }
        if (deviceInfo.getState() != DataState.Enable) {
            return ResultContent.buildFail("设备不可用");
        }

        boolean hasPermission = false;
        String projectOid = deviceInfo.getProjectOid();
        stopWatch.start("查询绑定的设备权限");
        DevicePermiss devicePermiss = devicePermissDao.findTopByUserIdAndDeviceIdAndProjectOidAndDataState(userId, deviceId, projectOid, DataState.Enable);
        if (ObjectUtils.isNotEmpty(devicePermiss)) {
            hasPermission = true;
        }
        stopWatch.stop();

        if (!hasPermission) {

            stopWatch.start("查询用户项目权限数据");
            Map<String, UserCacheModel> map = userPermissDataCacheService.getUserAndDeviceCacheData(userId, deviceId, projectOid);
            stopWatch.stop();

            UserCacheModel userCacheModel = map.get(userId);
            stopWatch.start("查询当前时间段");
            // 查找当前时间对应的时段信息
            List<PermissTimeSlot> permissTimeSlots = getCurrentTimeSlot(projectOid);
            stopWatch.stop();

            if (userCacheModel != null && userCacheModel.isSuccess() && ObjectUtils.isNotEmpty(permissTimeSlots)) {
                // 查看权限规则 是否包含该设备
                PermissSettingListSearch search = new PermissSettingListSearch();

                search.setProjectOid(projectOid);
                List<String> permissSettingIds = new ArrayList<>();
                permissTimeSlots.parallelStream().forEach(it -> {
                    if (ObjectUtils.isNotEmpty(it.getPermissSettingIds())) {
                        permissSettingIds.addAll(it.getPermissSettingIds());
                    }
                });
                search.setPermissSettingIds(permissSettingIds);

                // 用户关联的权限
                search.setSex(userCacheModel.getSex());
                search.setDataIds(userCacheModel.getDataIds());

                UserCacheModel deviceCacheModel = map.get(deviceId);

                if (deviceCacheModel != null && deviceCacheModel.isSuccess()) {
                    search.setDeviceTypes(List.of(deviceCacheModel.getDeviceType()));
                    // 设备所在的分组
                    search.setDeviceIds(deviceCacheModel.getDataIds());

                    stopWatch.start("规则数据查询");
                    boolean b = permissSettingListDao.isExit(search);
                    if (b) {
                        hasPermission = true;
                    } else {
                        msg = "未查询到权限";
                    }
                    stopWatch.stop();
                } else {
                    hasPermission = false;
                    if (ObjectUtils.isEmpty(deviceCacheModel)) {
                        msg = "设备权限为空";
                    } else if (!deviceCacheModel.isSuccess()) {
                        msg = deviceCacheModel.getMsg();
                    }
                }
            } else {
                hasPermission = false;
                if (ObjectUtils.isEmpty(permissTimeSlots)) {
                    msg = "规则时间段为空";
                } else if (ObjectUtils.isEmpty(userCacheModel)) {
                    msg = "用户权限数据为空";
                } else if (!userCacheModel.isSuccess()) {
                    msg = userCacheModel.getMsg();
                }
            }
        }
        deviceUserParam.setUseTime(stopWatch.getTotalTimeMillis());
        log.info("权限验证：{} {}", stopWatch.prettyPrint(), msg);
        if (!hasPermission) {
            return ResultContent.buildFail(msg);
        }
        return ResultContent.buildSuccess(msg);
    }

    /**
     * 查询当前时间所在的时间段信息
     *
     * @return
     */
    public List<PermissTimeSlot> getCurrentTimeSlot(String projectOid) {
        List<PermissTimeSlot> list = new ArrayList<>();
        List<PermissTimeSlot> allList = permissTimeSlotDao.findByProjectOidAndStateAndType(projectOid, DataState.Enable, TimeSlotType.Week);
        if (ObjectUtils.isNotEmpty(allList)) {
            Long currentTime = System.currentTimeMillis();
            WeekDayType weekDayType = DateUtils.getTimeWeekData(currentTime);
            int timeNumber = Integer.parseInt(DateUtils.paresTime(currentTime, "HHmm"));

            allList.parallelStream().forEach(it -> {
                List<TimeSlotWeekModel> timeSlotWeekModels = it.getTimeSlotWeekModels();
                if (ObjectUtils.isNotEmpty(timeSlotWeekModels)) {

                    // 筛选星期时间和是否有时间段
                    List<TimeSlotWeekModel> _tempWeek = timeSlotWeekModels.parallelStream().filter(time -> {
                        return time.getWeekDayType() == weekDayType && ObjectUtils.isNotEmpty(time.getTimeSlots());
                    }).collect(Collectors.toList());

                    _tempWeek.parallelStream().forEach(time -> {
                        boolean exits = time.getTimeSlots().parallelStream().anyMatch(slotModel -> {
                            return slotModel.getStartTimeNumber() < timeNumber && timeNumber < slotModel.getEndTimeNumber();
                        });
                        if (exits) {
                            list.add(it);
                        }
                    });
                }
            });
        }
        return list;
    }

    /**
     * 验证当前时间是否在时间段里
     *
     * @param list
     * @return
     */
    public boolean verifyTimeSlot(List<PermissTimeSlot> list) {
        boolean b = false;
        if (ObjectUtils.isNotEmpty(list)) {
            WeekDayType weekDayType = DateUtils.getTimeWeekData(System.currentTimeMillis());

            List<TimeSlotModel> timeSlots = new ArrayList<>();
            list.parallelStream().forEach(it -> {
                if (it.getState() == DataState.Enable) {
                    if (it.getType() == TimeSlotType.Week) {
                        List<TimeSlotWeekModel> timeSlotWeekModels = it.getTimeSlotWeekModels();
                        if (ObjectUtils.isNotEmpty(timeSlotWeekModels)) {
                            timeSlotWeekModels.parallelStream().forEach(time -> {
                                if (time.getWeekDayType() == weekDayType && ObjectUtils.isNotEmpty(time.getTimeSlots())) {
                                    timeSlots.addAll(time.getTimeSlots());
                                }
                            });
                        }
                    }
                }
            });

            if (ObjectUtils.isNotEmpty(timeSlots)) {
                int time = Integer.parseInt(DateUtils.paresTime(System.currentTimeMillis(), "HHmm"));
                List<TimeSlotModel> temp = timeSlots.parallelStream().filter(it -> {
                    return it.getStartTimeNumber() < time && time < it.getEndTimeNumber();
                }).collect(Collectors.toUnmodifiableList());
                if (ObjectUtils.isNotEmpty(temp)) {
                    b = true;
                }
            }
        }
        return b;
    }

}
