package com.zksy.gas.utils;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSONObject;
import com.zksy.api.domain.WarningThreshold;
import com.zksy.api.service.EarlyWarningAutoService;
import com.zksy.api.service.WarningThresholdService;
import com.zksy.api.domain.AlarmData;
import com.zksy.api.service.AlarmDataService;
import com.zksy.api.utils.AlarmLevelUtil;
import com.zksy.api.utils.SmsUtil;
import com.zksy.common.exception.InvalidMessageException;
import com.zksy.gas.domain.GasMonitorData;
import com.zksy.gas.service.GasMonitorDataService;
import com.zksy.utils.DevicePhoneFetchUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.ReadTimeoutException;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
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.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@ChannelHandler.Sharable
@Slf4j
@Component
public class MessageHandler extends ChannelInboundHandlerAdapter {
	private static Logger logger = LoggerFactory.getLogger(MessageHandler.class);
	private final GasMonitorDataService service;
	@Autowired
	private WarningThresholdService warningThresholdService;
	@Autowired
	private AlarmDataService alarmDataService;
	@Autowired
	private EarlyWarningAutoService earlyWarningAutoService;
	@Autowired
	private SmsUtil smsUtil;
	@Autowired
    private DevicePhoneFetchUtil devicePhoneFetchUtil;
    @Autowired
    private AlarmUtil alarmUtil;
    @Autowired
    private RestTemplate restTemplate;

    @Value("${device.status.api.url:http://zk-api-service/equipmentStatus/updateAlarmStatus}")
    private String deviceStatusApiUrl;

	@Autowired
	public MessageHandler(GasMonitorDataService firefightingPressureService) {
		this.service = firefightingPressureService;
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		super.channelActive(ctx);
		//sendDataToDevice(ctx);
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) {
		try {
			ByteBuf msgByteBuf = (ByteBuf) msg;
			if (msgByteBuf == null || !msgByteBuf.isReadable()) {
				logger.warn("接收到无效的消息");
				return;
			}
			int readable = msgByteBuf.readableBytes();
			byte[] msgBytes = new byte[readable];
			msgByteBuf.readBytes(msgBytes);
			logger.info("接收到 {} 字节的数据: {}, 来自: {}",
					readable, ProtocolUtils.bytesToHex(msgBytes), ctx.channel().remoteAddress());

			int checksumTotalLength = 2; // 末尾2字节校验码（如ED34）
			int bodyStartOffset = 16;    // 校验和07的主体起始索引
			int fullDataStartOffset = 3; // 校验和16的完整数据起始索引

			// 校验报文长度合法性
			if (readable < fullDataStartOffset + checksumTotalLength) {
				throw new InvalidMessageException("报文长度不足，无法完成校验");
			}

			int bodyEndOffset = msgBytes.length - checksumTotalLength; // 避开末尾2字节校验码
			int bodyLength = bodyEndOffset - bodyStartOffset;
			if (bodyLength <= 0) {
				throw new InvalidMessageException("主体数据长度无效，无法计算校验和07");
			}
			int checksum07 = DataCheckUtil.calcSumOnly(msgBytes, bodyStartOffset, bodyLength);

			int fullDataEndOffset = msgBytes.length - 1; // 包含倒数第二个字节
			int fullDataLength = fullDataEndOffset - fullDataStartOffset;
			if (fullDataLength <= 0) {
				throw new InvalidMessageException("完整数据长度无效，无法计算校验和16");
			}
			int checksum16 = DataCheckUtil.calcChecksum(msgBytes, fullDataStartOffset, fullDataLength);

			int calculatedChecksum = (checksum07 << 8) | checksum16;
			int receivedChecksum = ((msgBytes[msgBytes.length - 2] & 0xFF) << 8)
					| (msgBytes[msgBytes.length - 1] & 0xFF);

			// 打印调试信息，确认拼接结果
			logger.debug("校验和07（高8位，仅求和）: {}", Integer.toHexString(checksum07).toUpperCase());
			logger.debug("校验和16（低8位，FF-求和）: {}", Integer.toHexString(checksum16).toUpperCase());
			logger.debug("修改后拼接校验码: {}", Integer.toHexString(calculatedChecksum).toUpperCase());
			logger.debug("报文携带校验码: {}", Integer.toHexString(receivedChecksum).toUpperCase());

			if (calculatedChecksum != receivedChecksum) {
				throw new InvalidMessageException(
						String.format("数据校验失败：本地计算（07+16）=%04X（07=%02X, 16=%02X），报文携带=%04X",
								calculatedChecksum, checksum07, checksum16, receivedChecksum));
			}

			com.zksy.gas.domain.GasMonitorData resultData = DataParser.parseMessage(msgBytes);
			resultData.setId(java.util.UUID.randomUUID().toString());
			service.save(resultData);
			checkIfSmsAlertNeeded(resultData);
			logger.info("数据解析入库成功: {}", resultData);

		} catch (InvalidMessageException e) {
			logger.error("数据校验失败: {}", e.getMessage());
			ctx.writeAndFlush(Unpooled.copiedBuffer("数据校验失败".getBytes()));
		} catch (Exception e) {
			logger.error("数据解析/入库异常", e);
			ctx.writeAndFlush(Unpooled.copiedBuffer("数据处理异常".getBytes()));
		} finally {
			ReferenceCountUtil.release(msg);
		}
	}

	private String printHexBinary(byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for (byte b : bytes) {
			sb.append(String.format("%02X ", b));
		}
		System.out.println("Received raw data: " + sb.toString());
		logger.info("Received raw data: " + sb.toString());
		return sb.toString();
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		if (cause instanceof ReadTimeoutException) {
			logger.info("来自" + ctx.channel().remoteAddress() + "的连接超时断开");
		} else {
			cause.printStackTrace();
			logger.info("来自" + ctx.channel().remoteAddress() + "的连接异常断开");
			ctx.close();
		}
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.flush();
	}

	@Override
	public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
		logger.info("来自" + ctx.channel().remoteAddress() + "的连接主动断开");
		ctx.fireChannelUnregistered();
	}

	// 主动向设备发送数据
	public void sendDataToDevice(ChannelHandlerContext ctx) {
		try {
			// 将字符串形式的十六进制数据转换为字节数组
			String hexData = "01 03 00 00 00 01 84 0A ";
			String[] hexArray = hexData.split(" ");
			byte[] dataBytes = new byte[hexArray.length];
			for (int i = 0; i < hexArray.length; i++) {
				dataBytes[i] = (byte) Integer.parseInt(hexArray[i], 16);
			}
			ByteBuf byteBuf = Unpooled.copiedBuffer(dataBytes);
			ctx.writeAndFlush(byteBuf);
			logger.info("已向设备发送数据: {}", printHexBinary(dataBytes));
		} catch (Exception e) {
			logger.error("发送数据失败: {}", e.getMessage());
		}
	}
	public void checkIfSmsAlertNeeded(GasMonitorData resultData){
        //用MAC地址作为设备的设备编号
        String deviceId = resultData.getMacAddress();
        boolean hasAlarm = false;

		//获取温度阈值
		String temWarningCode = "WARN-GAS-TEMPERATURE";
		WarningThreshold temThreshold = checkThreshold(deviceId, temWarningCode);
		Double temMinValue = temThreshold != null ? temThreshold.getMinValue() : null;
		Double temMaxValue = temThreshold != null ? temThreshold.getMaxValue() : null;
		String temWarningType = temThreshold != null ? temThreshold.getWarningType() : "可燃气体温度预警";
		String temRemark = temThreshold != null ? temThreshold.getRemark() : null;

		//获取湿度阈值
		String humWarningCode = "WARN-GAS-HUMIDITY";
		WarningThreshold humThreshold = checkThreshold(deviceId, humWarningCode);
		Double humMinValue = humThreshold != null ? humThreshold.getMinValue() : null;
		Double humMaxValue = humThreshold != null ? humThreshold.getMaxValue() : null;
		String humWarningType = humThreshold != null ? humThreshold.getWarningType() : "湿度预警";
		String humRemark = humThreshold != null ? humThreshold.getRemark() : null;

		//获取气体浓度阈值
		String gasWarningCode = "WARN-GAS-CONCENTRATION";
		WarningThreshold gasThreshold = checkThreshold(deviceId, gasWarningCode);
		Double gasMinValue = gasThreshold != null ? gasThreshold.getMinValue() : null;
		Double gasMaxValue = gasThreshold != null ? gasThreshold.getMaxValue() : null;
		String gasWarningType = gasThreshold != null ? gasThreshold.getWarningType() : "气体浓度预警";
		String gasRemark = gasThreshold != null ? gasThreshold.getRemark() : null;

		//判断温度
		float temperature = resultData.getTemperature();
		boolean temperatureIsOverThreshold = false;
		if (temMinValue != null && temperature <= temMinValue) {
			temperatureIsOverThreshold = true;
		}
		if (temMaxValue != null && temperature >= temMaxValue) {
			temperatureIsOverThreshold = true;
		}
		BigDecimal temMinBd = temMinValue != null ? BigDecimal.valueOf(temMinValue) : null;
		BigDecimal temMaxBd = temMaxValue != null ? BigDecimal.valueOf(temMaxValue) : null;
		BigDecimal temActualBd = BigDecimal.valueOf(temperature);
		if (temMinValue != null || temMaxValue != null) {
			if (temperatureIsOverThreshold) {
					int alarmLevel = saveAlarmData(deviceId, temWarningType, temWarningCode,
							temMinBd, temMaxBd, temActualBd, temRemark != null ? temRemark : "可燃气体温度报警");
					earlyWarningAutoService.closeAutoWarning(deviceId, temWarningCode, "已达报警阈值，转报警处理");
					hasAlarm = true;
					if (alarmLevel == 1) {
					sendMessage(deviceId, temWarningType, resultData.getLongitude(), resultData.getLatitude());
				}
			} else {
				earlyWarningAutoService.checkAndGenerate(deviceId, temWarningType, temWarningCode,
						temMinBd, temMaxBd, temActualBd, temRemark);
			}
		}

		//判断湿度
		float humidity = resultData.getHumidity();
		boolean humidityIsOverThreshold = false;
		if (humMinValue != null && humidity <= humMinValue) {
			humidityIsOverThreshold = true;
		}
		if (humMaxValue != null && humidity >= humMaxValue) {
			humidityIsOverThreshold = true;
		}
		BigDecimal humMinBd = humMinValue != null ? BigDecimal.valueOf(humMinValue) : null;
		BigDecimal humMaxBd = humMaxValue != null ? BigDecimal.valueOf(humMaxValue) : null;
		BigDecimal humActualBd = BigDecimal.valueOf(humidity);
		if (humMinValue != null || humMaxValue != null) {
			if (humidityIsOverThreshold) {
					int alarmLevel = saveAlarmData(deviceId, humWarningType, humWarningCode,
							humMinBd, humMaxBd, humActualBd, humRemark != null ? humRemark : "可燃气体湿度报警");
					earlyWarningAutoService.closeAutoWarning(deviceId, humWarningCode, "已达报警阈值，转报警处理");
					hasAlarm = true;
					if (alarmLevel == 1) {
					sendMessage(deviceId, humWarningType, resultData.getLongitude(), resultData.getLatitude());
				}
			} else {
				earlyWarningAutoService.checkAndGenerate(deviceId, humWarningType, humWarningCode,
						humMinBd, humMaxBd, humActualBd, humRemark);
			}
		}

		//判断气体浓度
		BigDecimal gasConcentration = resultData.getGasConcentration();
		float actualGasConcentration = gasConcentration != null ? gasConcentration.floatValue() : 0f;
		boolean concentrationIsOverThreshold = false;
		if (gasMinValue != null && actualGasConcentration <= gasMinValue) {
			concentrationIsOverThreshold = true;
		}
		if (gasMaxValue != null && actualGasConcentration >= gasMaxValue) {
			concentrationIsOverThreshold = true;
		}
		BigDecimal gasMinBd = gasMinValue != null ? BigDecimal.valueOf(gasMinValue) : null;
		BigDecimal gasMaxBd = gasMaxValue != null ? BigDecimal.valueOf(gasMaxValue) : null;
		if ((gasMinValue != null || gasMaxValue != null) && gasConcentration != null) {
			if (concentrationIsOverThreshold) {
					int alarmLevel = saveAlarmData(deviceId, gasWarningType, gasWarningCode,
							gasMinBd, gasMaxBd, gasConcentration, gasRemark != null ? gasRemark : "可燃气体浓度报警");
					earlyWarningAutoService.closeAutoWarning(deviceId, gasWarningCode, "已达报警阈值，转报警处理");
					hasAlarm = true;
					if (alarmLevel == 1) {
					sendMessage(deviceId, gasWarningType, resultData.getLongitude(), resultData.getLatitude());
				}
			} else {
				earlyWarningAutoService.checkAndGenerate(deviceId, gasWarningType, gasWarningCode,
						gasMinBd, gasMaxBd, gasConcentration, gasRemark);
			}
		}

		//获取到的数据逐一进行判断
		Map<String, Boolean> alarmBits = resultData.parseAlarmBits();
		if(alarmBits.get("unknownAlarm")){
				saveAlarmDataLevelOne(deviceId, "未知报警", "WARN-UNKNOWN", null, "可燃气体未知报警");
				sendMessage(deviceId,"未知报警",resultData.getLongitude(),resultData.getLatitude());
				hasAlarm = true;
			}
			if(alarmBits.get("highAlarm")){
				saveAlarmDataLevelOne(deviceId, "高报警", "WARN-HIGH", null, "可燃气体高报警");
				sendMessage(deviceId,"高报警",resultData.getLongitude(),resultData.getLatitude());
				hasAlarm = true;
			}
		if(alarmBits.get("overRange")){
			saveAlarmDataLevelOne(deviceId, "超量程", "WARN-OVER-RANGE", null, "可燃气体超量程报警");
			sendMessage(deviceId,"超量程",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("calibrationCycle")){
			saveAlarmDataLevelOne(deviceId, "标定周期", "WARN-CALIBRATION-CYCLE", null, "可燃气体标定周期报警");
			sendMessage(deviceId,"标定周期",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("overLife")){
			saveAlarmDataLevelOne(deviceId, "超寿命", "WARN-OVER-LIFE", null, "可燃气体超寿命报警");
			sendMessage(deviceId,"超寿命",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("fallAlarm")){
			saveAlarmDataLevelOne(deviceId, "跌倒报警", "WARN-FALL", null, "可燃气体跌倒报警");
			sendMessage(deviceId,"跌倒报警",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("undervoltage")){
			saveAlarmDataLevelOne(deviceId, "欠压报警", "WARN-UNDERVOLTAGE", null, "可燃气体欠压报警");
			sendMessage(deviceId,"欠压报警",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("rangeAlarm")){
			saveAlarmDataLevelOne(deviceId, "区间报警", "WARN-RANGE", null, "可燃气体区间报警");
			sendMessage(deviceId,"区间报警",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("keyAlarm")){
			saveAlarmDataLevelOne(deviceId, "按键报警", "WARN-KEY", null, "可燃气体按键报警");
			sendMessage(deviceId,"按键报警",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("vibrationAlarm")){
			saveAlarmDataLevelOne(deviceId, "震动报警", "WARN-VIBRATION", null, "可燃气体震动报警");
			sendMessage(deviceId,"震动报警",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("waterLevelAlarm")){
			saveAlarmDataLevelOne(deviceId, "水位报警", "WARN-WATER-LEVEL", null, "可燃气体水位报警");
			sendMessage(deviceId,"水位报警",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("powerOffAlarm")){
			saveAlarmDataLevelOne(deviceId, "断电报警", "WARN-POWER-OFF", null, "可燃气体断电报警");
			sendMessage(deviceId,"断电报警",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("sensorFault")){
			saveAlarmDataLevelOne(deviceId, "传感器故障", "WARN-SENSOR-FAULT", null, "可燃气体传感器故障");
			sendMessage(deviceId,"传感器故障",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("overHumidity")){
			saveAlarmDataLevelOne(deviceId, "超湿报警", "WARN-OVER-HUMIDITY", null, "可燃气体超湿报警");
			sendMessage(deviceId,"超湿报警",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("overTemperature")){
			saveAlarmDataLevelOne(deviceId, "超温报警", "WARN-OVER-TEMPERATURE", null, "可燃气体超温报警");
			sendMessage(deviceId,"超温报警",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
		}
		if(alarmBits.get("systemFault")){
			saveAlarmDataLevelOne(deviceId, "系统故障", "WARN-SYSTEM-FAULT", null, "可燃气体系统故障");
			sendMessage(deviceId,"系统故障",resultData.getLongitude(),resultData.getLatitude());
			hasAlarm = true;
			}

			// 同步设备报警状态到 equipment_status 表
			updateDeviceAlarmStatus(deviceId, hasAlarm ? 1 : 0);
		}

		private WarningThreshold checkThreshold(String deviceCode, String warningCode) {
		try {
			return warningThresholdService.getWarningThresholdByDeviceAndCode(deviceCode, warningCode);
		} catch (Exception e) {
			log.error("查询预警阈值失败：deviceCode={}, warningCode={}", deviceCode, warningCode, e);
			return null;
		}
	}

	private int saveAlarmData(String deviceCode, String warningType, String warningCode,
							  BigDecimal minValue, BigDecimal maxValue,
							  BigDecimal actualValue, String remark) {
		int alarmLevel = 4;
		try {
			AlarmData alarmData = new AlarmData();
			alarmData.setDeviceCode(deviceCode);
			alarmData.setWarningType(warningType);
			alarmData.setWarningCode(warningCode);
			alarmData.setMinValue(minValue);
			alarmData.setMaxValue(maxValue);
			alarmData.setActualValue(actualValue);

			alarmLevel = AlarmLevelUtil.calculateLevel(actualValue, minValue, maxValue);
			BigDecimal deviationRatio = AlarmLevelUtil.calculateDeviationRatio(actualValue, minValue, maxValue);
			alarmData.setAlarmLevel(alarmLevel);
			alarmData.setDeviationRatio(deviationRatio);

			alarmData.setAlarmStatus(0);
			alarmData.setAlarmTime(LocalDateTime.now());
			alarmData.setRemark(remark);
			alarmData.setCreateTime(LocalDateTime.now());
			alarmDataService.saveAlarmData(alarmData);

			if (alarmLevel == 1) {
				log.warn("【1级紧急告警】deviceCode={}, warningCode={}, deviationRatio={}%",
						deviceCode, warningCode, deviationRatio);
			}
			log.info("告警数据入库成功: deviceCode={}, warningCode={}, level={}级", deviceCode, warningCode, alarmLevel);
		} catch (Exception e) {
			log.error("保存告警数据失败", e);
		}
		return alarmLevel;
	}

	private void saveAlarmDataLevelOne(String deviceCode, String warningType, String warningCode,
									   BigDecimal actualValue, String remark) {
		try {
			AlarmData alarmData = new AlarmData();
			alarmData.setDeviceCode(deviceCode);
			alarmData.setWarningType(warningType);
			alarmData.setWarningCode(warningCode);
			alarmData.setActualValue(actualValue);
			alarmData.setAlarmLevel(1);
			alarmData.setAlarmStatus(0);
			alarmData.setAlarmTime(LocalDateTime.now());
			alarmData.setRemark(remark);
			alarmData.setCreateTime(LocalDateTime.now());
			alarmDataService.saveAlarmData(alarmData);
			log.info("设备主动告警入库(1级): deviceCode={}, warningCode={}", deviceCode, warningCode);
		} catch (Exception e) {
			log.error("保存告警数据失败", e);
		}
	}
	//构造发送短信参数&&发送短信
	public void sendMessage(String deviceNo, String alarmType, BigDecimal lng, BigDecimal lat){
		// 构造短信参数
		JSONObject params = new JSONObject();
		params.put("deviceNo", deviceNo);
		params.put("alarmType", alarmType);
		// 经纬度处理（位置）
		params.put("location", String.format("经纬度：%.6f,%.8f", lng, lat));
		List<String> phoneListByDeviceId = devicePhoneFetchUtil.getPhoneListByDeviceId(deviceNo);
		Map<String, Boolean> sendResults = smsUtil.sendBatchSms(phoneListByDeviceId, params.toJSONString());
		log.info("发送信息完成");
    }

    /**
     * 更新设备报警状态
     * @param deviceCode 设备编码
     * @param alarmStatus 报警状态：0-正常，1-报警
     */
    private void updateDeviceAlarmStatus(String deviceCode, int alarmStatus) {
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("deviceCode", deviceCode);
            params.put("alarmStatus", alarmStatus);

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);

            restTemplate.postForObject(deviceStatusApiUrl, request, Map.class);
            log.info("设备报警状态更新成功: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus);
        } catch (Exception e) {
            log.error("更新设备报警状态失败: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus, e);
        }
    }
}