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

import cn.hutool.json.JSONObject;
import com.github.microservice.core.util.os.SystemUtil;
import com.github.microservice.dataConfig.IotIdentifierConfig;
import com.github.microservice.models.device.DevicePerQuery;
import com.github.microservice.models.devicePermiss.DeviceAboutPermiss;
import com.github.microservice.models.devicePermiss.DeviceUsersInfo;
import com.github.microservice.models.devicePermiss.GateWayPermissModel;
import com.github.microservice.models.devicePermiss.ProjectUserPermiss;
import com.github.microservice.models.iot.IotSendParam;
import com.github.microservice.net.ResultContent;
import com.google.common.collect.Lists;
import com.zhongshu.card.client.utils.DateUtils;
import com.zhongshu.card.server.core.dao.devices.DeviceInfoDao;
import com.zhongshu.card.server.core.dao.devices.DevicePermissSendLogDao;
import com.zhongshu.card.server.core.dataConfig.TtlConfig;
import com.zhongshu.card.server.core.domain.devices.DeviceInfo;
import com.zhongshu.card.server.core.domain.devices.permiss.DevicePermissSendLog;
import com.zhongshu.card.server.core.event.DevicePermissChangeEvent;
import com.zhongshu.card.server.core.event.UserInfoChangeSyncEvent;
import com.zhongshu.card.server.core.service.openAPI.OpenApiRequestService;
import com.zhongshu.card.server.core.util.CommonUtil;
import lombok.SneakyThrows;
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.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 设备 用户 权限发生变化监听
 *
 * @author TRX
 * @date 2024/10/11
 */
@Slf4j
@Service
public class DevicePermissEventService {

    @Autowired
    private DeviceInfoDao deviceInfoDao;

    @Autowired
    private OpenApiRequestService openApiRequestService;

    @Autowired
    private DevicePermissIotService devicePermissIotService;

    //线程池
    private ExecutorService executorService = Executors.newFixedThreadPool(SystemUtil.getCpuCoreCount() * 2);

    @Autowired
    private DevicePermissService devicePermissService;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private DevicePermissSendLogDao devicePermissSendLogDao;

    @Autowired
    private DevicePermissSendLogService devicePermissSendLogService;

    @Autowired
    private void init(ApplicationContext applicationContext) {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            executorService.shutdownNow();
        }));
    }

    /**
     * 通知用户关联信息发送变化
     *
     * @param userId
     * @param projectOid
     */
    public void sendUserInfoChangeEvent(String userId, String projectOid, String from) {
        UserInfoChangeSyncEvent event = new UserInfoChangeSyncEvent(this, List.of(userId), projectOid, from);
        applicationContext.publishEvent(event);
    }

    public void sendUserInfoChangeEvent(String userId, String projectOid, Map<String, Object> map) {
        UserInfoChangeSyncEvent event = new UserInfoChangeSyncEvent(this, List.of(userId), projectOid, map);
        applicationContext.publishEvent(event);
    }

    /**
     * 通知用户关联信息发送变化
     *
     * @param userIds
     * @param projectOid
     */
    public void sendUserInfoChangeEvent(List<String> userIds, String projectOid, String from) {
        UserInfoChangeSyncEvent event = new UserInfoChangeSyncEvent(this, userIds, projectOid, from);
        applicationContext.publishEvent(event);
    }

    /**
     * 设备信息发送变化
     *
     * @param deviceIds
     * @param projectOid
     */
    public void sendDeviceChangeEvent(List<String> deviceIds, String projectOid, String from) {
        DevicePermissChangeEvent event = new DevicePermissChangeEvent(this, deviceIds, projectOid, from);
        applicationContext.publishEvent(event);
    }

    public void sendDeviceChangeEvent(String deviceId, String projectOid, String from) {
        DevicePermissChangeEvent event = new DevicePermissChangeEvent(this, List.of(deviceId), projectOid, from);
        applicationContext.publishEvent(event);
    }

    //todo 不要监听这个了 2024-12-30
//    @EventListener(classes = DevicePermissChangeEvent.class)
    @SneakyThrows
    public void devicePermissChange(DevicePermissChangeEvent event) {
        executorService.execute(() -> {
            log.info("设备权限发生变化...");
            // 通知物联网 设备权限发生变化
            List<String> deviceIds = event.getDeviceIds();
            if (ObjectUtils.isNotEmpty(deviceIds)) {
                HashMap<String, List<String>> map = deviceGroupByGateWayId(deviceIds);
                if (!map.isEmpty()) {
                    String projectOid = event.getProjectOid();
                    // 遍历发送
                    map.keySet().stream().forEach(gateWayId -> {
                        List<String> _deviceIds = map.get(gateWayId);
                        try {
                            while (_deviceIds.size() > 0) {
                                // 统计网关管理的所有设备
                                int index = Math.min(_deviceIds.size(), IotIdentifierConfig.maxNoticeSize);
                                List<String> subList = _deviceIds.subList(0, index);
                                _deviceIds = _deviceIds.subList(index, _deviceIds.size());

                                sendDeviceAboutUsers(gateWayId, subList, projectOid);
                                sendDeviceAboutUserInfo(gateWayId, subList, projectOid);
                                if (!_deviceIds.isEmpty()) {
                                    TimeUnit.SECONDS.sleep(10);
                                }
                            }
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    });
                }
            }
        });
    }

    /**
     * 用户信息发生变化
     *
     * @param event
     */
    @EventListener(classes = UserInfoChangeSyncEvent.class)
    @SneakyThrows
    public void userInfoChange(UserInfoChangeSyncEvent event) {
        // 用户信息发送变化
        String projectOid = event.getProjectOid();
        final List<String>[] userIds = new List[]{event.getUserIds()};
        log.info("userInfoChange; {} {}", projectOid);
        if (StringUtils.isNotEmpty(projectOid) && ObjectUtils.isNotEmpty(userIds[0])) {
            executorService.execute(() -> {
                String groupId = event.getGroupId();
                userIds[0] = userIds[0].stream().distinct().collect(Collectors.toList());
                // 循环用户数据
                for (String userId : userIds[0]) {
                    List<String> deviceIds = devicePermissService.getUserAllDeviceIds(projectOid, List.of(userId));
                    // 网关 对应的设备
                    HashMap<String, List<String>> map = deviceGroupByGateWayId(deviceIds);
                    if (!map.isEmpty()) {
                        // 遍历发送
                        map.keySet().stream().forEach(gateWayId -> {
                            DeviceUsersInfo deviceUsersInfo = new DeviceUsersInfo();
                            deviceUsersInfo.setGroupId(groupId);
                            deviceUsersInfo.setGateWayId(gateWayId);
                            // 用户数据 (去重)
                            List<ProjectUserPermiss> userPermiss = devicePermissIotService.getUserPermiss(projectOid, userIds[0]);
                            deviceUsersInfo.setUsers(userPermiss);
                            // 下发用户数据
                            requestDevicesUsersData(deviceUsersInfo, projectOid);
                        });
                    }
                }
            });
        }
    }

    /**
     * 清除所有所有数据
     *
     * @param deviceIds
     * @param projectOid
     */
    public void clearDevicesAllBindUser(List<String> deviceIds, String projectOid) {
        if (ObjectUtils.isNotEmpty(deviceIds) && StringUtils.isNotEmpty(projectOid)) {
            executorService.execute(() -> {
                HashMap<String, List<String>> map = deviceGroupByGateWayId(deviceIds);
                map.keySet().stream().forEach(gateWayId -> {
                    GateWayPermissModel gateWayPermissModel = new GateWayPermissModel();
                    gateWayPermissModel.setGateWayId(gateWayId);
                    List<String> _deviceIds = map.get(gateWayId);

                    List<DeviceAboutPermiss> permisses = new ArrayList<DeviceAboutPermiss>();
                    for (String deviceId : _deviceIds) {
                        DeviceAboutPermiss permiss = new DeviceAboutPermiss();
                        permiss.setDeviceId(deviceId);
                        permiss.setMark(2);
                        permiss.setUserIds(Lists.newArrayList());
                        permisses.add(permiss);
                    }
                    gateWayPermissModel.setDevices(permisses);
                    requestDeviceBindData(gateWayPermissModel, projectOid);
                });
            });
        }
    }

    /**
     * 发送设备关联的用户数据
     *
     * @param gateWayId
     * @param deviceIds
     * @param projectOid
     */
    public void sendDeviceAboutUsers(String gateWayId, List<String> deviceIds, String projectOid) {
        DevicePerQuery query = new DevicePerQuery();
        query.setDeviceIds(deviceIds);
        query.setGateWayId(gateWayId);
        GateWayPermissModel gateWayPermissModel = devicePermissIotService.queryDevicePermissInfo(query);
        requestDeviceBindData(gateWayPermissModel, projectOid);
    }

    /**
     * 请求下发设备关联的用户
     *
     * @param gateWayPermissModel
     * @param projectOid
     */
    public void requestDeviceBindData(GateWayPermissModel gateWayPermissModel, String projectOid) {
        String gateWayId = gateWayPermissModel.getGateWayId();
        IotSendParam param = new IotSendParam();
        param.setGateWayId(gateWayId);
        param.setIdentifier(IotIdentifierConfig.queryDeviceBindUsers);

        String groupId = gateWayPermissModel.getGroupId();
        if (ObjectUtils.isNotEmpty(gateWayPermissModel.getDevices()) && StringUtils.isNotEmpty(groupId)) {
            List<DevicePermissSendLog> list = new ArrayList<>();
            for (DeviceAboutPermiss deviceAboutPermiss : gateWayPermissModel.getDevices()) {
                deviceAboutPermiss.setDataId(CommonUtil.UUID());

                DevicePermissSendLog sendLog = new DevicePermissSendLog();
                sendLog.setDataId(deviceAboutPermiss.getDataId());
                sendLog.setGateWayId(gateWayId);
                sendLog.setDeviceId(deviceAboutPermiss.getDeviceId());
                sendLog.setGroupId(groupId);
                sendLog.setData(gateWayPermissModel);
                sendLog.setSendTime(DateUtils.paresTime(System.currentTimeMillis(), DateUtils.FORMAT_LONG));
                sendLog.setEvent(IotIdentifierConfig.queryDeviceBindUsers);
                sendLog.setTtl(new Date(System.currentTimeMillis() + TtlConfig.permissLogTTl));
                list.add(sendLog);
            }
            devicePermissSendLogDao.saveAll(list);
        }

        // 组装消息内容
        JSONObject jsonObject = gateWayPermissModel.toJson();
        param.setData(jsonObject);
        ResultContent resultContent = openApiRequestService.sendIotMessage(param, projectOid);
        if (resultContent.isSuccess()) {
            log.info("设备权限下发成功");
        } else {
            log.error("设备权限下发失败 网关ID：{} {}", gateWayId, resultContent.getMsg());
        }
        devicePermissSendLogService.markPermissSend(groupId, resultContent.isSuccess(), resultContent.getMsg());
    }

    /**
     * 下发用户信息
     *
     * @param gateWayId
     * @param deviceIds
     * @param projectOid
     */
    public void sendDeviceAboutUserInfo(String gateWayId, List<String> deviceIds, String projectOid) {
        DevicePerQuery query = new DevicePerQuery();
        query.setDeviceIds(deviceIds);
        query.setGateWayId(gateWayId);
        DeviceUsersInfo deviceUsersInfo = devicePermissIotService.queryDeviceAboutUsers(query);
        requestDevicesUsersData(deviceUsersInfo, projectOid);
    }

    /**
     * 请求下发用户信息发生变化
     *
     * @param deviceUsersInfo
     * @param projectOid
     */
    public void requestDevicesUsersData(DeviceUsersInfo deviceUsersInfo, String projectOid) {
        String gateWayId = deviceUsersInfo.getGateWayId();
        IotSendParam param = new IotSendParam();
        param.setGateWayId(gateWayId);
        param.setIdentifier(IotIdentifierConfig.queryDeviceUsersInfo);

        String groupId = deviceUsersInfo.getGroupId();
        if (ObjectUtils.isNotEmpty(deviceUsersInfo.getUsers()) && StringUtils.isNotEmpty(groupId)) {
            List<DevicePermissSendLog> list = new ArrayList<>();
            for (ProjectUserPermiss projectUserPermiss : deviceUsersInfo.getUsers()) {
                projectUserPermiss.setDataId(CommonUtil.UUID());
                DevicePermissSendLog sendLog = new DevicePermissSendLog();
                sendLog.setDataId(projectUserPermiss.getDataId());
                sendLog.setGateWayId(gateWayId);
                sendLog.setUserId(projectUserPermiss.getUid());
                sendLog.setUserId(projectUserPermiss.getUn());
                sendLog.setGroupId(groupId);
                sendLog.setData(projectUserPermiss);
                sendLog.setSendTime(DateUtils.paresTime(System.currentTimeMillis(), DateUtils.FORMAT_LONG));
                sendLog.setEvent(IotIdentifierConfig.queryDeviceUsersInfo);
                sendLog.setTtl(new Date(System.currentTimeMillis() + TtlConfig.permissLogTTl));
                list.add(sendLog);
            }
            devicePermissSendLogDao.saveAll(list);
        }

        // 组装消息内容
        JSONObject jsonObject = deviceUsersInfo.toJson();
        param.setData(jsonObject);
        ResultContent resultContent = openApiRequestService.sendIotMessage(param, projectOid);
        if (resultContent.isSuccess()) {
            log.info("用户信息下发成功");
        } else {
            log.error("用户信息下发失败 网关ID：{} {}", gateWayId, resultContent.getMsg());
        }
        devicePermissSendLogService.markPermissSend(groupId, resultContent.isSuccess(), resultContent.getMsg());
    }

    /**
     * 设备以网关分组
     *
     * @param deviceIds
     * @return
     */
    public HashMap<String, List<String>> deviceGroupByGateWayId(List<String> deviceIds) {
        HashMap<String, List<String>> map = new HashMap<>();
        if (ObjectUtils.isNotEmpty(deviceIds)) {
            List<DeviceInfo> deviceInfos = deviceInfoDao.findByDeviceIdIn(deviceIds);
            if (ObjectUtils.isNotEmpty(deviceInfos)) {
                deviceInfos.stream().forEach(it -> {
                    String deviceId = it.getDeviceId();
                    String gateWayId = it.getGateWayId();
                    List<String> arr = List.of(gateWayId.split(","));
                    if (ObjectUtils.isNotEmpty(arr)) {
                        arr.stream().forEach(_gateWayId -> {
                            List<String> _list = map.get(_gateWayId);
                            if (ObjectUtils.isEmpty(_list)) {
                                _list = new ArrayList<>();
                            }
                            _list.add(deviceId);
                            map.put(_gateWayId, _list);
                        });
                    }
                });
            }
        }
        return map;
    }
}
