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.WarningThresholdService;
import com.zksy.api.utils.SmsUtil;
import com.zksy.common.exception.InvalidMessageException;
import com.zksy.pressure.domain.Enum.FirefightingDeviceCodeEnum;
import com.zksy.pressure.domain.Enum.FirefightingWarningCodeEnum;
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.stereotype.Component;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
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 service;
	@Autowired
	private SmsUtil smsUtil;
	@Autowired
	private DevicePhoneFetchUtil devicePhoneFetchUtil;
	@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();
			//1、获取到压力阈值
			Double warningValue = null;
			//1.1获取到设备编码
			String deviceWarningCode = FirefightingDeviceCodeEnum.FIREFIGHTING_DEVICE.getCode();
			FirefightingWarningCodeEnum targetWarningType=FirefightingWarningCodeEnum.PRESSURE;

			String warningCode = targetWarningType.getCode();
			String warningMsg = targetWarningType.getName();
			try {
				//1.2根据设备编码获取压力阈值
				WarningThreshold threshold = service.getWarningThresholdByDeviceAndCode(deviceWarningCode, warningCode);
				warningValue = threshold.getWarningValue();
			} catch (Exception e) {
				log.error("查询预警阈值失败");
			}
			//1.2获取到实际压力值
			Double pressureValue = resultData.getPressureValue();
			boolean isOverThreshold = pressureValue > warningValue;
			//1.3超出了阈值则发送短信,设备编号这里不是很清楚
			if(isOverThreshold){
				sendMessage(deviceId,warningMsg,resultData.getLongitude(),resultData.getLatitude());
			}
			if(resultData.getD14()==1){
				sendMessage(deviceId,"压力变幅报警",resultData.getLongitude(),resultData.getLatitude());
			}
			if(resultData.getD13()==1){
				sendMessage(deviceId,"压力下下限报警",resultData.getLongitude(),resultData.getLatitude());
			}
			if(resultData.getD12()==1){
				sendMessage(deviceId,"压力上上限报警",resultData.getLongitude(),resultData.getLatitude());
			}
			if(resultData.getD11()==1){
				sendMessage(deviceId,"压力下线报警",resultData.getLongitude(),resultData.getLatitude());
			}
			if(resultData.getD10()==1){
				sendMessage(deviceId,"压力上限报警",resultData.getLongitude(),resultData.getLatitude());
			}
			if(resultData.getD9()==1){
				sendMessage(deviceId,"传感器状态",resultData.getLongitude(),resultData.getLatitude());
			}
			if(resultData.getD1()==1){
				sendMessage(deviceId,"倾斜报警1",resultData.getLongitude(),resultData.getLatitude());
			}
		} catch (Exception e) {
			log.error("设备报警处理失败");
		}

	}
	//构造发送短信参数&&发送短信
	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("发送信息完成");
	}
}