package com.zksy.pressure.utils;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.apache.hc.client5.http.utils.Hex;
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.pressure.domain.FirefightingPressure;
import com.zksy.pressure.service.FirefightingPressureService;
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 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 FirefightingPressureService firefightingPressureService;
	@Autowired
	private WarningThresholdService warningThresholdService;
	@Autowired
	private AlarmDataService alarmDataService;
	@Autowired
	private EarlyWarningAutoService earlyWarningAutoService;
	@Autowired
	private SmsUtil smsUtil;
	@Autowired
    private DevicePhoneFetchUtil devicePhoneFetchUtil;
    @Autowired
    private RestTemplate restTemplate;

    @Value("${device.status.api.url:http://zk-api-service/equipmentStatus/updateAlarmStatus}")
    private String deviceStatusApiUrl;
	@Autowired
	public MessageHandler(FirefightingPressureService firefightingPressureService) {
		this.firefightingPressureService = 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;
			}
			logger.info("接收到 {} 字节的数据，来自: {}", msgByteBuf.readableBytes(), ctx.channel().remoteAddress());
			byte[] msgBytes = new byte[msgByteBuf.readableBytes()];
			msgByteBuf.readBytes(msgBytes);
			String result = printHexBinary(msgBytes);
			String msgString = result.replaceAll("\\s", "");
			String CRCString = msgString.substring(msgString.length() - 4);
			String bodyResult = msgString.substring(0, msgString.length() - 4);
			String codeString = DataCheckUtil.crc16Tall(bodyResult);
			System.out.println("校验码：" + CRCString + "-----------生成的校验码：" + codeString);
			if (!CRCString.equals(codeString)) {
				throw new InvalidMessageException("数据校验不成功");
			} else {
				String hexString = Hex.encodeHexString(msgBytes).toUpperCase();
				String uploadEndFlag = hexString.substring(hexString.length() - 6, hexString.length() - 4);
				logger.info("成功！！！接收到 {} 字节的数据，来自: {}", msgString, ctx.channel().remoteAddress());
				FirefightingPressure resultData = DataParser.parseMessage(msgString);

				String functionCode = msgString.substring(20, 22);
				logger.info("生成的回复报文功能码: {}", functionCode);
				if("EF".equals(functionCode)){
					String responseMsg = buildResponseMessage(resultData.getTelemeteringStation(), resultData.getCentralStation(), resultData.getPassword(),resultData.getFunctionCode(), "0000", uploadEndFlag);
					logger.info("生成的回复报文: {}", responseMsg);
					byte[] messageBytes = hexStringToByteArray(responseMsg);
					ctx.channel().writeAndFlush(Unpooled.copiedBuffer(messageBytes));
					return;
				}

				resultData.setId(UUID.randomUUID().toString());
				// 更新设备最后一次接收数据的时间
				//String addressCode = resultData.getAddressCode();
				//DeviceOfflineCheckTask.deviceLastReceiveTimeMap.put(addressCode, new Date());
				firefightingPressureService.save(resultData);

				// 4. 构建回复报文
				String responseMsg = buildResponseMessage(resultData.getTelemeteringStation(), resultData.getCentralStation(), resultData.getPassword(), resultData.getFunctionCode(), resultData.getSerialNumber(), uploadEndFlag);
				logger.info("生成的回复报文: {}", responseMsg);
				byte[] messageBytes = hexStringToByteArray(responseMsg);
				ctx.channel().writeAndFlush(Unpooled.copiedBuffer(messageBytes));
				// 阈值监测：报警 + 接近阈值自动预警
				checkIfSmsAlertNeeded(resultData);
			}
		} catch (InvalidMessageException e) {
			logger.error("数据入库失败: {}", e.getMessage());
			ctx.writeAndFlush(Unpooled.copiedBuffer("数据入库失败".getBytes()));
		}
	}
	private byte[] hexStringToByteArray(String hexString) {
		// 校验输入合法性
		if (hexString == null || hexString.length() % 2 != 0) {
			throw new IllegalArgumentException("十六进制字符串长度必须为偶数，输入：" + hexString);
		}

		int len = hexString.length();
		byte[] data = new byte[len / 2];
		// 每2个十六进制字符转换为1个字节
		for (int i = 0; i < len; i += 2) {
			data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
					+ Character.digit(hexString.charAt(i + 1), 16));
		}
		return data;
	}

	/**
	 * 构建回复报文
	 * @param telemetryAddr 遥测站地址（来自上传报文）
	 * @param centerAddr 中心站地址（来自上传报文）
	 * @param password 密码（来自上传报文）
	 * @param funcCode 功能码（来自上传报文）
	 * @param serialNo 流水号（来自上传报文）
	 * @param uploadEndFlag 上传报文结束符（03/17）
	 * @return 完整的回复报文十六进制字符串（包含CRC）
	 */
	private String buildResponseMessage(String telemetryAddr, String centerAddr, String password,
										String funcCode, String serialNo, String uploadEndFlag) {
		// 1. 固定字段
		String frameHeader = "7E7E"; // 帧头
		String downLen = "8008";    // 下行/载荷长度
		String msgStartFlag = "02"; // 报文起始符

		// 2. 动态字段 - 发报时间（当前时间，格式：年月日时分秒，十六进制）
		String sendTime = DataCheckUtil.getCurrentTimeHex();

		// 3. 回复报文结束符（上传是03则回复04，上传是17则回复06）
		String responseEndFlag = "04";
		if ("17".equals(uploadEndFlag)) {
			responseEndFlag = "06";
		}

		// 4. 拼接回复报文主体（不含CRC）
		StringBuilder bodyBuilder = new StringBuilder();
		bodyBuilder.append(frameHeader)          // 帧头 7E7E
				.append(telemetryAddr)        // 遥测站地址
				.append(centerAddr)           // 中心站地址
				.append(password)             // 密码
				.append(funcCode)             // 功能码
				.append(downLen)              // 下行/载荷长度
				.append(msgStartFlag)         // 报文起始符
				.append(serialNo)             // 流水号
				.append(sendTime)             // 发报时间
				.append(responseEndFlag);     // 报文结束符
		String body = bodyBuilder.toString();
		System.out.println("回复报文主体：" + body);
		// 5. 计算CRC16校验码
		String crc = DataCheckUtil.crc16Tall(body);
		// 6. 拼接最终报文（主体 + CRC）
		return body + crc;
	}
	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(FirefightingPressure resultData){
			try {
				//用遥测站地址作为设备的设备编号
				String deviceId = resultData.getTelemeteringStation();
				boolean hasAlarm = false;

				//1、获取到压力阈值
				String warningCode = "WARN-PRESSURE";
				WarningThreshold threshold = null;
				try {
					//1.2根据设备编码获取压力阈值
					threshold = warningThresholdService.getWarningThresholdByDeviceAndCode(deviceId, warningCode);
				} catch (Exception e) {
					log.error("查询预警阈值失败");
				}

				String warningType = threshold != null ? threshold.getWarningType() : "压力预警";
				String remark = threshold != null ? threshold.getRemark() : null;
				Double minValue = threshold != null ? threshold.getMinValue() : null;
				Double maxValue = threshold != null ? threshold.getMaxValue() : null;

				//1.2获取到实际压力值
				Double pressureValue = resultData.getPressureValue();
				if (pressureValue != null && (minValue != null || maxValue != null)) {
					BigDecimal minBd = minValue != null ? BigDecimal.valueOf(minValue) : null;
					BigDecimal maxBd = maxValue != null ? BigDecimal.valueOf(maxValue) : null;
					BigDecimal actualBd = BigDecimal.valueOf(pressureValue);

					boolean isOverThreshold = false;
					if (minValue != null && pressureValue <= minValue) {
						isOverThreshold = true;
					}
					if (maxValue != null && pressureValue >= maxValue) {
						isOverThreshold = true;
					}
					if (isOverThreshold) {
						int alarmLevel = saveAlarmData(deviceId, warningType, warningCode,
								minBd, maxBd, actualBd, remark != null ? remark : "压力报警");
						earlyWarningAutoService.closeAutoWarning(deviceId, warningCode, "已达报警阈值，转报警处理");
						hasAlarm = true;
						if (alarmLevel == 1) {
							sendMessage(deviceId, warningType, resultData.getLongitude(), resultData.getLatitude());
						}
					} else {
						earlyWarningAutoService.checkAndGenerate(deviceId, warningType, warningCode,
								minBd, maxBd, actualBd, remark);
					}
				}
				if(resultData.getD14()==1){
					saveAlarmDataLevelOne(deviceId, "压力变幅报警", "WARN-PRESSURE-VARY", null, "压力变幅报警");
					sendMessage(deviceId,"压力变幅报警",resultData.getLongitude(),resultData.getLatitude());
					hasAlarm = true;
				}
				if(resultData.getD13()==1){
					saveAlarmDataLevelOne(deviceId, "压力下下限报警", "WARN-PRESSURE-LOW-LOW", null, "压力下下限报警");
					sendMessage(deviceId,"压力下下限报警",resultData.getLongitude(),resultData.getLatitude());
					hasAlarm = true;
				}
				if(resultData.getD12()==1){
					saveAlarmDataLevelOne(deviceId, "压力上上限报警", "WARN-PRESSURE-HIGH-HIGH", null, "压力上上限报警");
					sendMessage(deviceId,"压力上上限报警",resultData.getLongitude(),resultData.getLatitude());
					hasAlarm = true;
				}
				if(resultData.getD11()==1){
					saveAlarmDataLevelOne(deviceId, "压力下线报警", "WARN-PRESSURE-LOW", null, "压力下线报警");
					sendMessage(deviceId,"压力下线报警",resultData.getLongitude(),resultData.getLatitude());
					hasAlarm = true;
				}
				if(resultData.getD10()==1){
					saveAlarmDataLevelOne(deviceId, "压力上限报警", "WARN-PRESSURE-HIGH", null, "压力上限报警");
					sendMessage(deviceId,"压力上限报警",resultData.getLongitude(),resultData.getLatitude());
					hasAlarm = true;
				}
				if(resultData.getD9()==1){
					saveAlarmDataLevelOne(deviceId, "传感器状态", "WARN-SENSOR-STATUS", null, "传感器状态");
					sendMessage(deviceId,"传感器状态",resultData.getLongitude(),resultData.getLatitude());
					hasAlarm = true;
				}
				if(resultData.getD1()==1){
					saveAlarmDataLevelOne(deviceId, "倾斜报警1", "WARN-TILT-1", null, "倾斜报警1");
					sendMessage(deviceId,"倾斜报警1",resultData.getLongitude(),resultData.getLatitude());
					hasAlarm = true;
				}

				// 同步设备报警状态到 equipment_status 表
				updateDeviceAlarmStatus(deviceId, hasAlarm ? 1 : 0);
			} catch (Exception e) {
				log.error("设备报警处理失败", e);
			}

		}

	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);
			}
		}
	}