package com.agri.framework.interceptor;

import com.agri.common.core.domain.entity.SysUser;
import com.agri.common.utils.wechat.WxUtil;
import com.agri.framework.config.MqttConfig;
import com.agri.framework.manager.MqttAutoOffManager;
import com.agri.system.domain.SysAgriInfo;
import com.agri.system.domain.SysAgriLimit;
import com.agri.system.domain.SysDevOperLog;
import com.agri.system.domain.SysMessage;
import com.agri.system.mapper.SysUserMapper;
import com.agri.system.service.ISysAgriInfoService;
import com.agri.system.service.ISysAgriLimitService;
import com.agri.system.service.ISysDevOperLogService;
import com.agri.system.service.ISysUserService;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * 前端控制指令处理器
 * 核心功能：
 * 1. 解析前端控制指令，校验入参合法性
 * 2. 前端操作设备权限校验
 * 3. 分布式锁控制，避免同设备同功能并发指令
 * 4. 转发前端指令到设备端
 * 适配JDK 8，无心跳包相关逻辑
 */
@Component
public class FrontendControlHandler {
    /**
     * 优化：统一使用SLF4J日志（JDK 8兼容）
     */
    private static final Logger log = LoggerFactory.getLogger(FrontendControlHandler.class);

    /**
     * Redis模板，用于存储订阅关系、设备在线状态、分布式锁
     */
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * MQTT消息发送工具类（由MqttConfig配置类注入）
     */
    @Resource
    private MqttConfig.MqttMessageSender mqttMessageSender;

    @Resource
    private MqttAutoOffManager mqttAutoOffManager;

    @Autowired
    private ISysAgriLimitService agriLimitService;

    @Autowired
    private ISysAgriInfoService sysAgriInfoService;
    @Autowired
    private ISysDevOperLogService sysDevOperLogService;
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private ISysUserService sysUserService;
    private final ObjectMapper objectMapper = new ObjectMapper();
    @Value("${spring.mqtt.dtu-ctl-lock-ttl}")
    private int dtuCtlLockTTL;
    private static final Map<String, Function<SysAgriLimit, Integer>> LIMIT_MAP = new HashMap<>();
    static {
        LIMIT_MAP.put("jm1g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm1gLimit())));
        LIMIT_MAP.put("jm2g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm2gLimit())));
        LIMIT_MAP.put("jbg1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJbgLimit())));
        LIMIT_MAP.put("jm3g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm3gLimit())));
        LIMIT_MAP.put("jm2k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm2kLimit())));
        LIMIT_MAP.put("jm3k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm3kLimit())));
        LIMIT_MAP.put("jbk1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJbkLimit())));
        LIMIT_MAP.put("jm1k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm1kLimit())));
    }
    /**
     * 处理前端控制指令：权限校验+分布式锁+转发给设备
     */
    public void handle(String topic, String payload) throws MqttException {
        // 解析前端clientId、设备ID
        String[] parts = topic.split("/");
        String clientId = parts[1];
        String deviceId = parts[3];

        // 新增：入参非空校验（JDK 8兼容）
        if (!StringUtils.hasText(clientId) || !StringUtils.hasText(deviceId)) {
            log.error("【指令处理】clientId或deviceId为空，topic={}", topic);
            return;
        }
        // 1. 权限校验（示例：admin开头有全权限）
        if (!checkPermission(clientId, deviceId)) {
            String errorTopic = "frontend/" + clientId + "/dtu/" + deviceId + "/listener";
            mqttMessageSender.publish(errorTopic, "{\"msg\":\"无设备操作权限\"}");
            log.warn("【权限校验】前端{}操作设备{}失败", clientId, deviceId);
            return;
        }
        // 4. 转发指令到设备
        String deviceTopic = "dtu/" + deviceId + "/down";
        JSONObject payloadObj;
        try {
            payloadObj = JSON.parseObject(payload);
        } catch (Exception e) {
            log.error("【设备处理】JSON解析失败，payload={}", payload, e);
            return;
        }
        if (payloadObj.containsKey("read")) {
            mqttMessageSender.publish(deviceTopic, payload);
            log.info("【主动读取】设备{}主动读取，payload={}",deviceId, payload);
            return;
        }
        // 解析功能码（{"功能码":状态码}格式）
        Map<String, Integer> funcCodeMap = null;
        try {
            funcCodeMap = JSON.parseObject(payload, new TypeReference<Map<String, Integer>>() {
            });
        } catch (Exception e) {
            log.error("【指令处理】功能码解析失败，payload={}", payload, e);
            String errorTopic = "frontend/" + clientId + "/dtu/" + deviceId + "/listener";
            mqttMessageSender.publish(errorTopic, "{\"msg\":\"指令格式错误\"}");
            return;
        }
        if (funcCodeMap == null || funcCodeMap.isEmpty()) {
             String errorTopic = "frontend/" + clientId + "/dtu/" + deviceId + "/listener";
             mqttMessageSender.publish(errorTopic, "{\"msg\":\"功能码不能为空\"}");
            log.warn("【指令处理】前端{}操作设备{}失败：功能码为空", clientId, deviceId);
            return;
        }
        // 提取第一个功能码作为锁标识
        String funcType = funcCodeMap.keySet().iterator().next();

        // 2. 分布式锁：设备ID+功能类型（避免同设备同功能并发控制）
        String lockKey = "lock:" + deviceId + ":" + funcType;
        Boolean lockSuccess = stringRedisTemplate.opsForValue().setIfAbsent(
                lockKey, clientId, dtuCtlLockTTL, TimeUnit.SECONDS // 延长至15秒，适配设备回执场景
        );
        if (lockSuccess == null || !lockSuccess) {
            String errorTopic = "frontend/" + clientId + "/dtu/" + deviceId + "/listener";
            mqttMessageSender.publish(errorTopic, "{\"msg\":\"设备" + funcType + "功能忙，请稍后重试\",\"clientId\":\""+clientId+"\"}");
            log.warn("【分布式锁】前端{}操作设备{}的{}功能失败；可能其他用户正在操作此功能", clientId, deviceId, funcType);
            return;
        }

        try {
            // 3. 记录日志
            log.info("【指令处理】前端{}于{}控制设备{}的{}功能，指令：{}",
                    clientId, LocalDateTime.now(), deviceId, funcType, payload);
            SysUser sysUser = sysUserService.lambdaQuery()
                    .eq(SysUser::getClientId, clientId)
                    .one();
            String operator = "手动控制";
            if (sysUser!=null) {
                operator = sysUser.getUserName();
            }
            SysAgriInfo agriInfo = sysAgriInfoService.lambdaQuery()
                    .eq(SysAgriInfo::getImei, deviceId)
                    .one();
            String agriName = (agriInfo!=null && ObjectUtils.isNotEmpty(agriInfo.getAgriName()))?agriInfo.getAgriName():null;
            SysDevOperLog logDto = new SysDevOperLog();
            logDto.setAgriName(agriName);
            logDto.setImei(deviceId);
            logDto.setFuncCode(funcType);
            logDto.setOpType(funcCodeMap.get(funcType));
            logDto.setOpSource(1);
            logDto.setPayload(payload);
            logDto.setLockAcquired(1);
            logDto.setLockHolder(clientId);
            logDto.setCreateBy(operator);
            sysDevOperLogService.save(logDto);
            //todo
            mqttMessageSender.publish(deviceTopic, payload);
//        if (save) {
//            testAutoOffTask(deviceId,funcCodeMap);
//        }
            log.info("【指令转发】前端{} → 设备{}的{}功能", clientId, deviceId, funcType);
        } finally {
            stringRedisTemplate.delete(lockKey);
        }
    }

    public void testAutoOffTask(String deviceId, Map<String,Integer> funcCodeMap) throws MqttException {

        String funcType = funcCodeMap.keySet().iterator().next();
        Integer funcValue = funcCodeMap.get(funcType);
        // 释放对应功能的分布式锁
        String lockKey = "lock:" + deviceId + ":" + funcType;
        Boolean delete = stringRedisTemplate.delete(lockKey);
        if (delete) {
            log.info("【设备控制锁删除成功！】");
        }

        // 回执成功且值=1时启动自动关闭任务（保留原有逻辑）
        if (StringUtils.hasText(funcType) && funcValue != null && funcValue == 1) {
            SysAgriLimit agriLimit = agriLimitService.lambdaQuery()
                    .eq(SysAgriLimit::getImei, deviceId)
                    .one();
            int autoOffSeconds = 0;
            if (agriLimit != null) {
                autoOffSeconds = LIMIT_MAP.getOrDefault(funcType, k -> 0).apply(agriLimit);
            }
            // 新增：判断是否真的需要执行自动关任务（延迟秒数>0才是有效任务）
            if (autoOffSeconds > 0) {
                mqttAutoOffManager.scheduleAutoOff(deviceId, funcType, autoOffSeconds);
                log.debug("【自动关任务】标记需要执行，deviceId={}, funcType={}, delay={}s", deviceId, funcType, autoOffSeconds);

            } else {
                log.debug("【自动关任务】标记不符合执行运行时间未配置，deviceId={}, funcType={}, delay={}s", deviceId, funcType, autoOffSeconds);
            }

            sysDevOperLogService.lambdaUpdate()
                    .eq(SysDevOperLog::getImei, deviceId)
                    .eq(SysDevOperLog::getFuncCode, funcType)
                    .eq(SysDevOperLog::getOpType, funcValue)
                    .eq(SysDevOperLog::getLockAcquired,1)
                    .orderByDesc(SysDevOperLog::getCreateTime)
                    .last("LIMIT 1")
                    .set(SysDevOperLog::getAckReceived,1)
                    .set(SysDevOperLog::getIsLockSuc,1)
                    .set(SysDevOperLog::getAckSuc, 1)
                    .set(SysDevOperLog::getIsTask, 1)
                    .set(autoOffSeconds <= 0, SysDevOperLog::getNoTaskReason,"当前运行时间：【"+autoOffSeconds+"】")
                    .set(SysDevOperLog::getUpdateBy, "测试")
                    .set(SysDevOperLog::getExecResult, 1)
                    .update();
        }

        if (StringUtils.hasText(funcType) && funcValue != null && funcValue == 0)  {
            mqttAutoOffManager.cancelAutoOff(deviceId, funcType);
        }
    }
    /**
     * 权限校验逻辑（示例）
     * 可根据业务需求扩展：
     * 1. 管理员前端（clientId以admin_开头）拥有所有权限
     * 2. 普通前端仅能操作Redis中绑定的设备（user_device:{clientId} → deviceId集合）
     *
     * @param clientId 前端唯一标识
     * @param deviceId 设备ID
     * @return true=有权限，false=无权限
     */
    private boolean checkPermission(String clientId, String deviceId) {
        // 管理员权限：clientId以admin_开头
        // 普通用户权限：校验Redis中是否绑定该设备
        return Boolean.TRUE;
    }

    public void sendAlarmMessage(List<SysMessage> messages) throws Exception {
        if (CollectionUtils.isEmpty(messages)) {
            return;
        }
        for (SysMessage message : messages) {
            Map<String, Object> alarmMsg = new HashMap<>();
            alarmMsg.put("msg",message.getContent());
            alarmMsg.put("time", LocalDateTime.now().format(DATE_TIME_FORMATTER));
            String alarmMessage = objectMapper.writeValueAsString(alarmMsg);
            mqttMessageSender.publish("frontend/" + message.getImei() + "/alarm", alarmMessage);
        }
    }
}