package org.springblade.openinterface.nrtms;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.system.service.IParamService;
import org.springblade.openinterface.nrtms.handler.NrtmsEventHandler;
import org.springblade.smartapplication.facedevice.entity.FaceDevice;
import org.springblade.smartapplication.facedevice.service.IFaceDeviceService;
import org.springblade.smartapplication.smartmonitor.constant.ZHConstant;
import org.springblade.smartapplication.smartmonitor.entity.SmartVideoMonitor;
import org.springblade.smartapplication.smartmonitor.service.ISmartVideoMonitorService;
import org.springblade.utils.UploadController1;
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 javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

@RestController
@AllArgsConstructor
@Api(value = "实时网络监控监听剪口")
@Slf4j
public class NrtmsController {

	private final RedisTemplate<String, String> redisTemplate;
	private final ISmartVideoMonitorService smartVideoMonitorService;
	private final NrtmsEventHandler nrtmsEventHandler;
	private final IParamService paramService;
	private final static String ZH_DEVICE_INSTRUCT_COMMAND_SEQ = "zh:device:instruct:commonSeq";
	private final UploadController1 uploadController;
	private final IFaceDeviceService faceDeviceService;
	/**
	 * 纵横设备心跳请求
	 * @param deviceRequest 设备心跳信息
	 */
	@PutMapping(value = "/DeviceEndianHeartbeat")
	public Map<String, Object> DeviceEndianHeartbeat(@RequestBody Map<String, Object> deviceRequest){
		String serialNum = (String)deviceRequest.get("SerialNum");
		log.info("=====================心跳设备序列号【" + serialNum + "】=====================");
		Map<String, Object> map = new HashMap<>();
		map.put("ReturnCode", 0);
		map.put("ReturnStr", "OK");
		map.put("PushEventInfo", true);
		map.put("PushEventPic", true);
		Long size = redisTemplate.opsForList().size(serialNum + "_list"); //从缓存中获取待下发的指令
		Long size2 = redisTemplate.opsForList().size(serialNum + "_openDoor"); //从缓存中获取待下发的指令
		if(size > 0 || size2 >0){
			map.put("StartCommand", true);
		}else{
			map.put("StartCommand", false);
		}
		this.heartbeat(serialNum);
		return map;
	}

	/**
	 * 设备请求配置命令
	 * @param requestData
	 * @return
	 * @throws IOException
	 */
	@PutMapping("/DeviceEndianCommand")
	public Map<String, Object> DeviceEndianCommand(@RequestBody JSONObject requestData){
		String serialNum = requestData.getString("SerialNum");
		Integer commandSeq = requestData.getInteger("CommandSeq");
		if(commandSeq == null){ //表示请求配置命令
			String instructStr = this.redisTemplate.opsForList().rightPop(serialNum + "_list");
			String openDoorInstructStr = this.redisTemplate.opsForList().rightPop(serialNum + "_openDoor");
			log.info("===================纵横设备指令下发================");
//			log.info(instructStr);
			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表示要关门
					String interval = paramService.getValue("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(interval) * 1000);
				}
				return commandData;
			}
			if(StringUtils.isNotBlank(instructStr)){
				JSONObject commandData = JSONObject.parseObject(instructStr);
				log.info("===================纵横设备指令下发================");
				return commandData;
			}
			return new JSONObject();
		}else{ //表示返回下发的配置命令处理结果
			log.info("==================纵横设备指令下发回调================");
			log.info(requestData.toJSONString());
			String command = requestData.getString("Command");
			if(command.equals(ZHConstant.I8H.open_door.getCommand())){
				nrtmsEventHandler.handleOpenDoorRecord(serialNum, commandSeq, requestData);
			}
			//继续取下一个缓存下发给设备
			ListOperations<String, String> opsForList = this.redisTemplate.opsForList();
			String commandStr = opsForList.rightPop(serialNum + "_list");
			if(StringUtils.isNotBlank(commandStr)){
				JSONObject commandData = JSONObject.parseObject(commandStr);
				log.info("===================纵横设备指令下发================");
				log.info(commandData.toJSONString());
				return commandData;
			}
			return new JSONObject();
		}
	}

	/**
	 * 事件推送
	 * @param request 设备信息
	 * @return ResultBean<String>
	 */
	@PostMapping(value = "/DeviceEndianEvent")
	public Map<String, Object> DeviceEndianEvent(HttpServletRequest request	) throws IOException {
		MultipartHttpServletRequest params=((MultipartHttpServletRequest) request);
		MultiValueMap<String, MultipartFile> multiFileMap = params.getMultiFileMap();
		Map<String, Object> map = new HashMap<>();
		MultipartFile eventInfo = multiFileMap.get("EventInfo").get(0);
		byte[] bytes = eventInfo.getBytes();
		Map<String, Object> eventMap = JSONObject.parseObject(bytes, Map.class);
		List<MultipartFile> fileList = multiFileMap.get("file");
		String openNrtms = paramService.getValue("open_nrtms");
		if (openNrtms.equals("1")) {
			if(fileList != null && fileList.size() > 0){
				for(MultipartFile multipartFile : fileList){
					R<String> uploadR = uploadController.putFile(multipartFile);
					eventMap.put("img", uploadR.getData());
					break;
				}
			}
		}
		nrtmsEventHandler.handleEvent(eventMap, fileList);
//		ApiLog apiLog = new ApiLog();
//		apiLog.setMethodDesc("【DeviceEndianEvent】");
//		apiLog.setReqData(JSONUtil.toJsonStr(zhAccessRecordDto));
//		sysApiLogFeign.create(apiLog);
//		//出入门记录：
//		accessRecords.setSerialNumber(zhAccessRecordDto.getSerialNum());
//		ZHFaceCompareInfoDto faceCompareInfo = zhAccessRecordDto.getFaceCompareInfo();
//		ZHSnapDto zhSnapDto = faceCompareInfo.getSnap().get(0);
//		accessRecords.setUserId(zhSnapDto.getMatch().getId());
//		String similarity = zhSnapDto.getMatch().getSimilarity();
//		Float contrast = Float.parseFloat(similarity) / 100;
//		accessRecords.setContrast(contrast.toString());
//		accessRecords.setTemperature(zhSnapDto.getTemperature().getTemp());
//		String openType = zhSnapDto.getOpenType();
//		String accessDate = zhSnapDto.getTime();
//		if(openType.equals("1")){ //刷脸
//			accessRecords.setOpenDoorType(0);
//		}else if(openType.equals("2")){ //刷卡
//			accessRecords.setOpenDoorType(2);
//		}
//		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss+08");
//		try {
//			Date parse = sdf.parse(accessDate);
//			accessRecords.setAccessDate(parse);
//		} catch (ParseException e) {
//			e.printStackTrace();
//		}
//		//  获取设备信息
//		Device device = this.deviceFeign.getEntityBySerialNumber(accessRecords.getSerialNumber());
////        //  设备信息
//		accessRecords.setDeviceId(device.getId());
//		accessRecords.setDeviceName(device.getName());
//		accessRecords.setSerialNumber(device.getSerialNumber());
//		accessRecords.setInstallPath(device.getInstallPath());
//		accessRecords.setIsOut(device.getIsOut());
////        //  小区信息
//		accessRecords.setResidentialId(device.getXqId());
//		accessRecords.setResidentialName(device.getXqName());
////        //  机构信息
//		accessRecords.setOrgPosition(device.getOrgPosition());
//		accessRecords.setEstatePosition(device.getEstatePosition());
//		accessRecords.setRootOrgId(device.getRootOrgId());
//		this.accessRecordsFeign.addAccessRecords(accessRecords);
		map.put("ReturnCode", 0);
		return map;
	}

	/**
	 * 设备心跳检测接口
	 * @param serialNum 设备序列号
	 */
	@PostMapping(value = "/device/check/heartbeat")
	public R heartbeat(@RequestBody String serialNum){
		log.info("=====================心跳设备序列号【" + serialNum + "】=====================");
		LambdaQueryWrapper<SmartVideoMonitor> queryWrapper = new QueryWrapper<SmartVideoMonitor>().lambda();
		queryWrapper.eq(SmartVideoMonitor::getSerialNum, serialNum);
		SmartVideoMonitor target = smartVideoMonitorService.getOne(queryWrapper);
		if(target != null){
			target.setOnline(1);
			target.setHeartbeat(new Date());
			smartVideoMonitorService.updateById(target);
			return R.status(true);
		}
		LambdaQueryWrapper<FaceDevice> lambda = new QueryWrapper<FaceDevice>().lambda();
		lambda.eq(FaceDevice::getMacAddress, serialNum);
		FaceDevice faceDevice = faceDeviceService.getOne(lambda);
		if(faceDevice != null){
			faceDevice.setDeviceStatus(1);
			faceDevice.setUpdateTime(new Date());
			faceDeviceService.updateById(faceDevice);
			return R.status(true);
		}
		return R.status(true);
	}
}
