package cn.iocoder.yudao.module.infra.websocket;

import cn.hutool.json.JSONObject;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.websocket.core.attendance.AttendanceConstants;
import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener;
import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
import cn.iocoder.yudao.module.infra.websocket.dto.DeviceResponseDTO;
import cn.iocoder.yudao.module.infra.websocket.message.AttendanceSendMessage;
import cn.iocoder.yudao.module.system.api.equipment.AttendanceMachineApi;
import cn.iocoder.yudao.module.system.api.equipment.dto.AttendanceUpdateDTO;
import cn.iocoder.yudao.module.system.api.equipment.dto.DistributeRecordDTO;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.github.yulichang.toolkit.SpringContentUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.socket.WebSocketSession;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;

/**
 * 考勤仪设备 WebSocket 数据通信
 *

 */
@Component
public class AttendanceWebSocketMessageListener implements WebSocketMessageListener<AttendanceSendMessage> {

    @Resource
    private WebSocketMessageSender webSocketMessageSender;

    @Resource
    private AttendanceMachineApi attendanceMachineApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void onMessage(WebSocketSession session, AttendanceSendMessage message) {

        StringRedisTemplate redisTemplate = SpringContentUtils.getBean(StringRedisTemplate.class);

        JSONObject object1 = new JSONObject(message.getData());
        if (object1.get("cmd").equals(AttendanceConstants.CMD_TO_DEVICE)) {

            String requestId = IdWorker.get32UUID();
            object1.set("from", session.getId());
            object1.set("extra", requestId + "_" + message.getTo());

            JSONObject data = new JSONObject(object1.get("data"));
            // 插入设备请求记录
            List<DistributeRecordDTO> recordDTOs = new ArrayList<>();
            DistributeRecordDTO recordDTO = new DistributeRecordDTO();

            switch (data.get("cmd").toString()) {

                case "addUser":
                    recordDTO.setRequestId(requestId);
                    recordDTO.setDeviceNo(object1.get("to").toString());
                    recordDTO.setUserId(Long.valueOf(data.get("user_id").toString()));
                    recordDTO.setType(1);
                    recordDTO.setResult("通讯失败");
                    recordDTO.setCreator(message.getTo());
                    recordDTOs.add(recordDTO);
                    break;
                case "delMultiUser":
                    List<String> userIds = JsonUtils.parseArray(data.get("user_ids").toString(), String.class);
                    // 删除的用户Id 存在redis中
                    redisTemplate.opsForValue().set(object1.get("to").toString(), data.get("user_ids").toString());
                    for (String userId : userIds) {

                        DistributeRecordDTO deleteRecord = new DistributeRecordDTO();
                        deleteRecord.setRequestId(requestId);
                        deleteRecord.setDeviceNo(object1.get("to").toString());
                        deleteRecord.setUserId(Long.valueOf(userId));
                        deleteRecord.setType(0);
                        deleteRecord.setResult("通讯失败");
                        deleteRecord.setCreator(message.getTo());
                        recordDTOs.add(deleteRecord);
                    }
                    break;
            }
            attendanceMachineApi.createDistributeRecord(recordDTOs);

            // 发送命令至设备
            webSocketMessageSender.sendSNObject(object1.get("to").toString(), "attendance-message-send", object1);
        }

        if (object1.get("cmd").equals(AttendanceConstants.CMD_TO_CLIENT)) {

            // 获取响应数据
            DeviceResponseDTO dto = JsonUtils.parseObject2(object1.get("data").toString(), DeviceResponseDTO.class);

            // 获取设备号
            String deviceNo = object1.get("from").toString();
            String requestId = object1.get("extra").toString().split("_")[0];
            String userId = object1.get("extra").toString().split("_")[1];
            if (dto != null) {

                // 更新下发数据
                AttendanceUpdateDTO attendanceUpdateDTO = new AttendanceUpdateDTO();

                // 在事务提交后，更新下发记录，
                TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                    @Override
                    public void afterCommit() {

                        List<DistributeRecordDTO> recordDTOs = new ArrayList<>();

                        // 更新下发记录表
                        if (dto.getDelFailed() == null) {

                            DistributeRecordDTO recordDTO = new DistributeRecordDTO();
                            recordDTO.setCode(dto.getCode());
                            recordDTO.setResult(dto.getMsg());
                            recordDTO.setUserId(dto.getUserId() == null ? Long.valueOf(userId) : Long.valueOf(dto.getUserId()));
                            recordDTO.setRequestId(requestId);
                            recordDTO.setUpdater(userId);
                            recordDTOs.add(recordDTO);
                        } else {

                            // 更新下发记录表
                            for (DeviceResponseDTO.DeleteUser info : dto.getDelFailed()) {

                                DistributeRecordDTO deleteRecord = new DistributeRecordDTO();
                                deleteRecord.setCode(info.getCode());
                                deleteRecord.setResult(info.getMsg());
                                deleteRecord.setUserId(Long.valueOf(info.getUserId()));
                                deleteRecord.setRequestId(requestId);
                                deleteRecord.setUpdater(userId);
                                recordDTOs.add(deleteRecord);
                            }
                        }

                        // 更新下发记录表
                        attendanceMachineApi.updateDistributeRecord(recordDTOs);
                    }
                });

                // 响应失败的情况
                if (dto.getCode() != 0) {

                    if (!object1.get("to").toString().isEmpty()) {
                        webSocketMessageSender.sendObject(object1.get("to").toString(), "attendance-message-send", object1);
                    }else {

                        redisTemplate.opsForValue().set(deviceNo + "msg", dto.getCode() + "_" + dto.getMsg(), 30, TimeUnit.SECONDS);
                        redisTemplate.opsForValue().set(deviceNo, "false", 30, TimeUnit.SECONDS);
                    }

                    return;
                }

                switch (dto.getCmd()) {

                    case "addUserRet":
                        // 更新设备绑定用户信息
                        attendanceUpdateDTO.setUserId(Collections.singletonList(Long.valueOf(dto.getUserId())));
                        attendanceUpdateDTO.setDeviceNo(deviceNo);
                        attendanceUpdateDTO.setMethod(0);

                        // 更新设备绑定用户信息
                        attendanceMachineApi.updateAttendance(attendanceUpdateDTO);
                        break;
                    case "delMultiUserRet":
                        List<String> userIds = JsonUtils.parseArray(redisTemplate.opsForValue().get(deviceNo), String.class);
                        if (dto.getDelFailed() != null) {
                            userIds.removeAll(convertList(dto.getDelFailed(), DeviceResponseDTO.DeleteUser::getUserId));
                        }
                        // 更新设备绑定用户信息
                        attendanceUpdateDTO.setUserId(userIds.stream().map(Long::valueOf).collect(Collectors.toList()));
                        attendanceUpdateDTO.setDeviceNo(deviceNo);
                        attendanceUpdateDTO.setMethod(1);

                        // 更新设备绑定用户信息
                        attendanceMachineApi.updateAttendance(attendanceUpdateDTO);
                        break;
                    case "setPasswordRet":
                        // 更新设备密码
                        String value = redisTemplate.opsForValue().get(deviceNo);
                        if (value != null) {
                            String oldPassword = value.split("-")[0];
                            String newPassword = value.split("-")[1];
                            attendanceMachineApi.updateDevicePassword(deviceNo, oldPassword, newPassword);
                        }
                        break;
                }
                redisTemplate.delete(deviceNo);


            }

            if (!object1.get("to").toString().isEmpty()) {
                webSocketMessageSender.sendObject(object1.get("to").toString(), "attendance-message-send", object1);
            }


        }
    }

    @Override
    public String getType() {
        return "attendance-message-send";
    }

}
