package org.springblade.third.zongheng;

import cn.hutool.json.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.scala.DefaultScalaModule;
import com.fasterxml.jackson.module.scala.DefaultScalaModule$;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.map.Module;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.device.feign.IDoorDeviceClient;
import org.springblade.system.feign.ISysClient;
import org.springblade.third.constants.ZHConstant;
import org.springblade.third.zongheng.handler.DeviceEndEventHandlerFactory;
import org.springblade.third.zongheng.handler.IDeviceEndEventHandler;
import org.springblade.third.zongheng.handler.IDeviceEndianCommandHandler;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import scala.collection.Map;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

@RestController
@AllArgsConstructor
@Api(value = "纵横设备HTTP接口")
@Slf4j
public class ZHDeviceController {

	private final RedisTemplate<String, String> redisTemplate;
	private final IDoorDeviceClient doorDeviceClient;
	private final static String ZH_DEVICE_INSTRUCT_COMMAND_SEQ = "zh:device:instruct:commonSeq";
	private final ISysClient sysClient;

	/**
	 * 纵横设备心跳请求
	 * @param requestData 设备心跳信息
	 */
	@PutMapping(value = "/DeviceEndianHeartbeat")
	public JSONObject DeviceEndianHeartbeat(@RequestBody JSONObject requestData){
		String serialNum = requestData.getString("SerialNum");
		JSONObject returnData = new JSONObject();
		returnData.put("ReturnCode", 0);
		returnData.put("ReturnStr", "OK");
		returnData.put("PushEventInfo", true);
		returnData.put("PushEventPic", true);
		Long instructNum = redisTemplate.opsForList().size(serialNum + "_list"); //从缓存中获取待下发的指令
		Long openDoorInstructNum = redisTemplate.opsForList().size(serialNum + "_openDoor"); //从缓存中获取待下发的指令
		if(instructNum > 0 || openDoorInstructNum > 0){
			returnData.put("StartCommand", true);
		}else{
			returnData.put("StartCommand", false);
		}
		//更新最新心跳时间
		doorDeviceClient.heartbeat(serialNum);
		return returnData;
	}

	/**
	 * 设备请求配置命令
	 * @param
	 * @return
	 * @throws IOException
	 */
	@PutMapping("/DeviceEndianCommand")
	public JSONObject DeviceEndianCommand(@RequestBody Map<String, Object> map){
		JSONObject requestData = null;
		ObjectMapper objectMapper = new ObjectMapper();
		objectMapper.registerModule(new DefaultScalaModule());
		try {
			String s = objectMapper.writeValueAsString(map);
			requestData = JSONObject.parseObject(s);
		} catch (IOException e) {
			e.printStackTrace();
		}
		Integer commandSeq = requestData.getInteger("CommandSeq");
		String serialNum = requestData.getString("SerialNum");
		log.info("===================纵横设备指令请求数据================");
		log.info(requestData.toString());
		if(commandSeq == null){		//表示请求配置命令
			String instructStr = this.redisTemplate.opsForList().rightPop(serialNum + "_list");
			String openDoorInstructStr = this.redisTemplate.opsForList().rightPop(serialNum + "_openDoor");
			if(StringUtil.isNotBlank(openDoorInstructStr)){
				JSONObject commandData = JSONObject.parseObject(openDoorInstructStr);
				log.info("===================纵横设备开门指令下发================");
				log.info(commandData.toJSONString());
				JSONObject data = commandData.getJSONObject("Data");
				Integer workState = data.getInteger("WorkState");
				if(workState == 0){ //0表示开门，1表示要关门
					R<String> intervalR = sysClient.getParamValue("door_device_open_interval");
					Timer timer = new Timer();
					timer.schedule(new TimerTask() {
						@Override
						public void run() {
							//下发关门指令到redis，等下一次设备回来消费，定时5秒后发送
							HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
							String num = hashOperations.get(ZH_DEVICE_INSTRUCT_COMMAND_SEQ, serialNum);
							Integer commonSeq = 10;
							if(StringUtil.hasText(num)){
								commonSeq = Integer.parseInt(num) + 1;
								num = commonSeq + "";
							}else{
								num = "10"; //设备指令的commonSeq从10开始
							}
							JSONObject request = JSONObject.parseObject(openDoorInstructStr);
							JSONObject data = new JSONObject();
							data.put("WorkState", 1);
							request.put("Command", ZHConstant.I8H.open_door.getCommand());
							request.put("CommandSeq", commonSeq);
							request.put("Type", ZHConstant.I8H.open_door.getType());
							request.put("Data", data);
							redisTemplate.opsForList().leftPush(serialNum + "_openDoor", request.toJSONString());
							timer.cancel();
							this.cancel();
						}
					}, Integer.parseInt(intervalR.getData()) * 1000);
				}
				return commandData;
			}
			if(StringUtils.isNotBlank(instructStr)){
				JSONObject commandData = JSONObject.parseObject(instructStr);
				log.info("===================纵横设备指令下发================");
				log.info(commandData.toJSONString());
				return commandData;
			}
			return new JSONObject();
		}else{ 							//表示返回下发的配置命令处理结果
			log.info("==================纵横设备指令下发回调================");
			log.info(requestData.toString());
			//继续取下一个缓存下发给设备
			ListOperations<String, String> opsForList = this.redisTemplate.opsForList();
			String commandStr = opsForList.rightPop(serialNum + "_list");
			String command = requestData.getString("Command");
			IDeviceEndianCommandHandler commandHandler = DeviceEndEventHandlerFactory.getDeviceEndianCommandHandler(command);
			if(commandHandler != null){
				commandHandler.handle(requestData);
			}
			if(StringUtils.isNotBlank(commandStr)){
				JSONObject commandData = JSONObject.parseObject(commandStr);
				log.info("===================纵横设备指令下发================");
				log.info(commandData.toJSONString());
				return commandData;
			}
			return new JSONObject();
		}
	}

	/**
	 * 事件推送
	 * @param request 设备信息
	 * @return JSONObject
	 */
	@PostMapping(value = "/DeviceEndianEvent")
	public JSONObject DeviceEndianEvent(HttpServletRequest request) throws IOException {
		MultipartHttpServletRequest params=((MultipartHttpServletRequest) request);
		MultiValueMap<String, MultipartFile> multiFileMap = params.getMultiFileMap();
		MultipartFile eventInfo = multiFileMap.get("EventInfo").get(0);
		List<MultipartFile> file = multiFileMap.get("file");
		byte[] bytes = eventInfo.getBytes();
		JSONObject requestData = JSONObject.parseObject(bytes, JSONObject.class);
		String eventType = requestData.getString("EventType");
		IDeviceEndEventHandler eventHandler = DeviceEndEventHandlerFactory.getEventHandler(eventType);
		if(eventHandler != null){
			eventHandler.handle(requestData, file);
		}
		JSONObject returnData = new JSONObject();
		returnData.put("ReturnCode", 0);
		log.info("==================纵横设备事件上报================");
		log.info(requestData.toJSONString());
		return returnData;
	}

}
