package com.wsm.admin.device.tcp;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wsm.admin.constant.MsgCode;
import com.wsm.admin.model.Device;
import com.wsm.admin.model.DeviceEvent;
import com.wsm.admin.service.IDeviceEventService;
import com.wsm.admin.service.IDeviceService;
import com.wsm.admin.service.impl.DeviceEventServiceImpl;
import com.wsm.admin.service.impl.DeviceServiceImpl;
import com.wsm.common.util.DateTimeUtils;
import com.wsm.common.util.RedisUtil;
import com.wsm.common.util.SpringContext;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.simp.SimpMessagingTemplate;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 井盖事件处理
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
	private static final Logger log= LoggerFactory.getLogger(NettyServerHandler.class);


	private IDeviceService deviceService;

	private IDeviceEventService deviceEventService;

	private SimpMessagingTemplate messagingTemplate;

	private RedisUtil redisUtil;


//	@Autowired
//	private RedisTemplate<String, Object> redisTemplate;



	private static final Map<String, String> deviceStatusMap = new HashMap<>();


	private static final String JG_NORMAL = "00000000";

	private static final String JG_LOW_PRESSURE_CODE = "0xFF002F00";

	private static final String JG_LOW_PRESSURE_OFF = "0xFF002F01";

	/**
	 * 心跳响应
	 */
	private static final String JG_HEARTBEAT = "GET / HTTP/1.0";

	/**
	 * 井盖正常数据长度
	 */
	private static final Integer CHECK_DATA_LENGTH = 162;

	private static final double JG_ERC40 = 18;

	private static final double JG_ERC90 = 70;

	/**
	 * 心跳
	 */
	private static final int CODE_HEARTBEAT = 85;


	/**
	 * 报警
	 */
	private static final int CODE_ALARM = 0;




	static {
		deviceStatusMap.put(JG_NORMAL, "井盖正常");
		deviceStatusMap.put(JG_LOW_PRESSURE_CODE, "井盖低电告警 ");
		deviceStatusMap.put(JG_LOW_PRESSURE_OFF, "井盖低电关机");
		deviceStatusMap.put("ERC40", "井盖倾斜/抬起");
		deviceStatusMap.put("ERC90", "井盖掀翻");
	}


	public NettyServerHandler(){
		if (deviceService == null){
			deviceService = SpringContext.getBean(DeviceServiceImpl.class);
		}
		if (deviceEventService == null){
			deviceEventService = SpringContext.getBean(DeviceEventServiceImpl.class);
		}
		if (messagingTemplate == null){
			messagingTemplate = SpringContext.getBean(SimpMessagingTemplate.class);
		}
		if (redisUtil == null){
			redisUtil = SpringContext.getBean(RedisUtil.class);
		}
	}


	/**
     * 收到数据时调用
	 * @param ctx
     * @param msg
     * @throws Exception
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

		log.info("Time: {}", new SimpleDateFormat("yyyy.MM.dd HH:mm:ss.SSS").format(new Date()));
		log.info("客户端地址: {}", ctx.channel().remoteAddress());
		log.info("ID: {}", ctx.channel().id());
		try {
			ByteBuf in = (ByteBuf) msg;
			int readableBytes = in.readableBytes();
			byte[] bytes = new byte[readableBytes];
			in.readBytes(bytes);
			String inString = new String(bytes);
			log.info("接收data： {}", inString);



			if (StringUtils.isNotEmpty(inString) && inString.length() == CHECK_DATA_LENGTH){


				ConvertData cd = new ConvertData();
				Map<String, Object> hm = cd.convert(inString);


				log.info("解析json： {}", JSON.toJSONString(hm));

				int type = (int)hm.get("type");
				// 设备id
				String sn2 = hm.get("sn2").toString();


				// 心跳检测
				if (type == CODE_HEARTBEAT) {
					redisUtil.set(sn2,"heartbeat", Long.parseLong("25"));
					log.warn("heartbeat device id: {}", sn2);
					return;

				}


				String status = hm.get("status").toString();

				// 计算井盖角度
				String ox = hm.get("x").toString();
				String oy = hm.get("y").toString();
				double angle = angle(Double.parseDouble(ox), Double.parseDouble(oy));
				log.info("井盖开启角度： {} 度", Math.round(angle));


				Device device = deviceService.findByDeviceId(sn2);
				log.warn("JG设备号: {}", sn2);

				// 用来心跳检测
				redisUtil.set(sn2,"heartbeat",Long.parseLong("25"));

				// 上报时间
				String year = hm.get("yyyy").toString();
				String month = hm.get("MM").toString();
				String day = hm.get("dd").toString();
				String hh = hm.get("HH").toString();
				String mm = hm.get("mm").toString();
				String ss = hm.get("ss").toString();
				String time = "20"+year+"-"+month+"-"+day+" "+hh+":"+mm+":"+ss;
				Date postTime = DateTimeUtils.parse(time);
				log.warn("上报时间： {}", time);


				//报警开关
				boolean needEvent = false;
				String content = "";
				Integer devideStatus = null;


				// 状态类型：0-正常  1-报警  2-低压  3-故障
				if (device != null) {

					needEvent = true;

					// 低电压
					if (JG_LOW_PRESSURE_CODE.equals(status)) {
						device.setStatus((byte)2);
						devideStatus = 2;
						content = deviceStatusMap.get(JG_LOW_PRESSURE_CODE);

						// 故障
					} else if (JG_LOW_PRESSURE_OFF.equals(status)) {
						device.setStatus((byte)3);
						devideStatus = 3;
						content = deviceStatusMap.get(JG_LOW_PRESSURE_OFF);

						// 报警
					} else if (JG_NORMAL.equals(status)) {
						device.setStatus((byte)1);

						//处理报警类型
						devideStatus = 1;
						// 大于40度

						if (angle > JG_ERC40) {
							// 报警
							content = deviceStatusMap.get("ERC40");


						}
						if (angle > JG_ERC90) {
							content = deviceStatusMap.get("ERC90");

						}
					}
					device.setUpdateTime(new Date());
					deviceService.update(device);

					redisUtil.delete(MsgCode.REDIS_CYCLE_DEVICE_LIST);




					// 记录报警详情
					if (needEvent) {
						DeviceEvent event = deviceEventService.findByStatusAndDeviceId(device.getId(), devideStatus);
						if (event == null) {
							event = new DeviceEvent();
							event.setDevice(device);
							event.setCreateTime(new Date());
						}
						event.setStatus(devideStatus);
						// 处理状态：0-待解决, 1-已立案，2-出警中，3-已解决
						event.setHandleStatus((byte)0);
						event.setContent(content);
						event.setUpdateTime(new Date());
						event.setPostTime(postTime);
						deviceEventService.save(event);
						log.warn(device.getDeviceId() + "： " + content);


						JSONObject result = new JSONObject();
						result.put("id", device.getDeviceId());
						result.put("deviceType", device.getDeviceType());
						result.put("status", status);

						//推送信息到前端
						messagingTemplate.convertAndSend("/topic/device", result.toJSONString());

					}
				}
			}


		} finally {
			// 抛弃收到的数据
			ReferenceCountUtil.release(msg);
			log.warn("<<<<<<<<<end");
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		// 当出现异常就关闭连接
		cause.printStackTrace();
		ctx.close();
	}


	/**
	 * 获取角度
	 * @return
	 */
	private static double angle(double x, double y) {

		// 三轴计算
		// 计算因子
		double factor = 3.90625;

		double gx = x * factor;
		double gy = y * factor;

		double Axy =  Math.sqrt(gx * gx + gy * gy);

		if (Axy > 980) {
			Axy = 980;
		}

		Axy = Math.acos(Axy/980) * 180 / 3.1415;

		double angleXY = Axy;

		if ((Axy - angleXY) >= 0.5){
			angleXY += 1;
		}
		angleXY = 90 - angleXY;

//		System.out.println("angleXY: " + angleXY); // 23.574218229866414


		return angleXY;
	}

	public static void main(String[] args) {
		double x = -125;
		double y = -193;
		angle(x, y);
	}



}