package org.springblade.openinterface.iot.listener;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.alarm.alarmgroup.entity.AlarmGroup;
import org.springblade.alarm.alarmgroup.service.IAlarmGroupService;
import org.springblade.alarm.alarmgroupuser.entity.AlarmGroupUser;
import org.springblade.alarm.alarmgroupuser.service.IAlarmGroupUserService;
import org.springblade.community.residential.entity.Residential;
import org.springblade.community.residential.service.IResidentialService;
import org.springblade.core.log.logger.BladeLogger;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.util.EventBusFactorys;
import org.springblade.homecare.alarmlist.entity.Alarm;
import org.springblade.homecare.alarmlist.service.IAlarmService;
import org.springblade.jobs.devicejob.controller.DeviceJobController;
import org.springblade.jobs.devicejob.entity.DeviceJob;
import org.springblade.jobs.devicejob.service.IDeviceJobService;
import org.springblade.modules.system.entity.Dept;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.service.IDeptService;
import org.springblade.modules.system.service.IUserService;
import org.springblade.openinterface.dto.IotSmsSendDto;
import org.springblade.openinterface.dto.IotSmsTemplateParam;
import org.springblade.smartapplication.heartbeat.entity.DeviceHeartbeat;
import org.springblade.smartapplication.heartbeat.service.IDeviceHeartbeatService;
import org.springblade.smartapplication.smartsmoke.entity.SmartDevice;
import org.springblade.smartapplication.smartsmoke.service.ISmartDeviceService;
import org.springblade.system.orgposition.entity.OrgPosition;
import org.springblade.system.orgposition.service.IOrgPositionService;
import org.springblade.utils.ByteConvert;
import org.springblade.utils.OrderGenerateUtilService;
import org.springblade.utils.SerializableUtil;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import sun.misc.BASE64Decoder;

import java.io.IOException;
import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author zwx
 * @create 2020/12/13 13:58
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("openinterface/iot/listen")
public class IotSubscribeController {

	private ISmartDeviceService smartDeviceService;
	private IAlarmService alarmService;
	private IDeviceHeartbeatService deviceHeartbeatService;
	private BladeLogger logger;
	private IDeviceJobService deviceJobService;
	private RedisTemplate<String, String> redisTemplate;
	private IResidentialService residentialService;
	private IAlarmGroupService alarmGroupService;
	private IAlarmGroupUserService alarmGroupUserService;
	private OrderGenerateUtilService orderGenerateUtilService;
	private IUserService userService;
	private IDeptService deptService;
	private IOrgPositionService orgPositionService;


	@PostMapping("/device/dataReport")
	public R iotDeviceDataReport(@RequestBody Map<String, Object> map) throws Exception {
		log.error("dataReport --> " + JSONUtil.toJsonStr(map));
		logger.info("dataReport", JSONUtil.toJsonStr(map));

		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

		//判断是告警报告还是心跳报告： 02 心跳报告 03 告警上报
		Map payload = (Map) map.get("payload");
		String appData = payload.get("APPdata").toString();
		String appDataDecode = null;
		try {
			appDataDecode = new String((new BASE64Decoder()).decodeBuffer(appData));
		} catch (IOException e) {
			e.printStackTrace();
		}
		//设备状态位
		char[] status = appDataDecode.substring(10, 14).toCharArray();
		String heartOrAlarm = appDataDecode.substring(6, 8);
		String sensorParam = appDataDecode.substring(14, 22);
		char[] sensorParamToChar = sensorParam.toCharArray();
		//小端模式转化为大端模式
		ByteConvert.swap(sensorParamToChar);
		ByteConvert.swap(status);
		//设备状态位（二进制）
		String statusBinary = ByteConvert.parseHexStr2Byte(new String(status));

		//温度和浓度
		String temperatureAndConcentration = new String(sensorParamToChar);
		String temperature = temperatureAndConcentration.substring(0, 4);
		Integer deviceTemperature = Integer.parseInt(temperature, 16);
		String concentration = temperatureAndConcentration.substring(4, 8);
		Integer deviceConcentration = Integer.parseInt(concentration, 16);
		//电池电量
		String battery = appDataDecode.substring(22, 26);
		Integer deviceBattery = Integer.parseInt(battery, 16);

		String imei = map.get("IMEI").toString();
		SmartDevice smartDevice = smartDeviceService.getBaseMapper().selectOne(new QueryWrapper<>(new SmartDevice()).lambda().eq(SmartDevice::getImei, imei));

		sf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
		String timestamp = map.get("timestamp").toString();
		Date date = new Date(Long.valueOf(timestamp));
		if (heartOrAlarm.equals("02")) {//心跳报告
			smartDevice.setBattery(deviceBattery > 3200 ? String.valueOf(100) : String.valueOf(deviceBattery / 3200));
			smartDevice.setConcentration(deviceConcentration.toString());
			smartDevice.setTemperature(deviceTemperature.toString());

			//修改设备
			smartDeviceService.updateById(smartDevice);
			//保存心跳数据
			DeviceHeartbeat deviceHeartbeat = new DeviceHeartbeat();
			deviceHeartbeat.setBattery(deviceBattery > 3000 ? String.valueOf(100) : String.valueOf(deviceBattery / 3000));
			deviceHeartbeat.setConcentration(deviceConcentration.toString());
			deviceHeartbeat.setTemperature(deviceTemperature.toString());
			deviceHeartbeat.setImei(imei);
			deviceHeartbeat.setDeviceId(smartDevice.getDeviceId());
			deviceHeartbeat.setCreateTime(date);
			deviceHeartbeatService.save(deviceHeartbeat);

		} else if (heartOrAlarm.equals("03")) {//告警上报

			Alarm alarm = new Alarm();
			alarm.setDeviceId(smartDevice.getImei());
			alarm.setIsAlarm(1);
			alarm.setDeviceName(smartDevice.getDeviceName());
			alarm.setRecordTime(sf.format(date));
			alarm.setMonitorValue(deviceConcentration.toString());
			alarm.setDeviceType(Integer.valueOf(smartDevice.getDeviceType()));
			alarm.setAlarmType(1);
			alarm.setTenantId(smartDevice.getTenantId());
			StringBuffer sb = new StringBuffer();
			if (statusBinary.substring(7, 8).equals("1")) {
				sb.append("烟雾报警");
			}
			if (statusBinary.substring(6, 7).equals("1")) {
				sb.append("电池低压");
			}
			if (statusBinary.substring(5, 6).equals("1")) {
				sb.append("温度报警");
			}
			if (statusBinary.substring(4, 5).equals("1")) {
				sb.append("故障报警");
			}

			if (statusBinary.substring(3, 4).equals("1")) {
				sb.append("按键测试报警");
			}
			if (sb.length() == 0) {
				sb.append("正常告警");
				return R.data(true);
			}
			alarm.setAlarmDesc(sb.toString());
			alarm.setOrgPosition(smartDevice.getOrgPosition());
			alarm.setName(sb.toString());
			Alarm selectAlarm = new Alarm();
			selectAlarm.setAlarmDesc(alarm.getAlarmDesc());
			selectAlarm.setDeviceId(alarm.getDeviceId());
//			selectAlarm.setMonitorValue(alarm.getMonitorValue());

			//查询出与该告警记录一样的告警记录
			List<Alarm> alarms = alarmService.getBaseMapper().selectList(new QueryWrapper<>(selectAlarm).orderByDesc("record_time"));
			System.out.println(alarms);
			if (alarms.size() > 0) {
				Alarm alarm1 = alarms.get(0);
				if (alarm1.getOrderId() == null || alarm1.getOrderId().equals("")) {//未生成工单
					alarm1.setAlarmTimes(alarm1.getAlarmTimes() + 1);

					alarm1.setLastNoticeDate(sf.parse(alarm.getRecordTime()));

					alarmService.updateById(alarm1);
					//自动生成工单
					orderGenerateUtilService.deviceAlarmOrderGenerate(alarm);

//					sendSms(alarm);
					EventBusFactorys eventBusFactorys = EventBusFactorys.get();
					eventBusFactorys.getController("   ").post(alarm1);//发送短信
					eventBusFactorys.getController("alarmSendVoiceSubscriber").post(alarm1);//发送语音
					return R.status(true);
				} else if (alarm1.getOrderId() != null) {//已生成工单
					DeviceJob deviceJob = deviceJobService.getById(alarm1.getOrderId());
					if (deviceJob != null && deviceJob.getJobStatus() == 2) {//工单已完成

						boolean save = alarmService.save(alarm);//保存记录
						if (save) {
							//自动生成工单
							orderGenerateUtilService.deviceAlarmOrderGenerate(alarm);
							//通知后台管理账号
							saveAlarmToRedis(alarm,alarm.getOrgPosition(), alarm.getTenantId());
						}
//						sendSms(alarm);//新增告警记录时发送短信
						EventBusFactorys eventBusFactorys = EventBusFactorys.get();
						eventBusFactorys.getController("alarmSendSmsSubscriber").post(alarm);//发送短信
						eventBusFactorys.getController("alarmSendVoiceSubscriber").post(alarm);//发送语音
						return R.status(save);
					} else if (deviceJob != null && deviceJob.getJobStatus() == 1) {//未完成
						alarm1.setAlarmTimes(alarm1.getAlarmTimes() + 1);
						alarm1.setLastNoticeDate(sf.parse(alarm.getRecordTime()));
						EventBusFactorys eventBusFactorys = EventBusFactorys.get();
						eventBusFactorys.getController("alarmSendSmsSubscriber").post(alarm1);//发送短信
						eventBusFactorys.getController("alarmSendVoiceSubscriber").post(alarm1);//发送语音
						return R.status(alarmService.updateById(alarm1));
					}
				}
			} else {
				alarm.setAlarmTimes(1);

				alarmService.save(alarm);
				//自动生成工单
				orderGenerateUtilService.deviceAlarmOrderGenerate(alarm);
				//通知后台管理账号
				saveAlarmToRedis(alarm,alarm.getOrgPosition(), alarm.getTenantId());
//				sendSms(alarm);
				EventBusFactorys eventBusFactorys = EventBusFactorys.get();
				eventBusFactorys.getController("alarmSendSmsSubscriber").post(alarm);//发送短信
				eventBusFactorys.getController("alarmSendVoiceSubscriber").post(alarm);//发送语音
			}
		}


		return R.status(true);
	}

	@PostMapping("/device/commandResponse")
	public R iotDeviceCommandResponse(@RequestBody Map<String, Object> map) {
		log.error("commandResponse --> " + JSONUtil.toJsonStr(map));
		return R.status(true);
	}

	@PostMapping("/device/eventReport")
	public R iotDeviceEventReport(@RequestBody Map<String, Object> map) {
		log.error("eventReport --> " + JSONUtil.toJsonStr(map));
		return R.status(true);
	}

	@PostMapping("/device/deviceOnlineOfflineReport")
	public R iotDeviceDataReportTupUnion(@RequestBody Map<String, Object> map) {
		log.error("deviceOnlineOfflineReport --> " + JSONUtil.toJsonStr(map));
		logger.info("deviceOnlineOfflineReport", JSONUtil.toJsonStr(map));
		String deviceId = map.get("deviceId").toString();
		SmartDevice smartDevice = smartDeviceService.getBaseMapper().selectOne(new QueryWrapper<>(new SmartDevice()).lambda().eq(SmartDevice::getDeviceId, deviceId));

		String eventType = map.get("eventType").toString();
		smartDevice.setDefenseStatus(Integer.valueOf(eventType));
		smartDeviceService.updateById(smartDevice);
		return R.status(true);
	}


	/**
	 * 新增告警调用感知平台短信功能发送短信
	 *
	 * @param alarm
	 */
	private void sendSms(Alarm alarm) {
		RestTemplate restTemplate = new RestTemplate();
		//获取accessToken
		final String accessToken = redisTemplate.opsForValue().get("sptg:iot:auth:accessToken@#617fb531-c8bb-47c0-b3c4-d2fa4162a18e");
//

		log.error("accessToken" + accessToken);
//		String accessToken = "e02fdb5e-02c9-4eb4-b6b2-e0e52094d847";
		List<IotSmsSendDto> iotSmsSendDtos = buildIotSmsSendDto(alarm);
		iotSmsSendDtos.parallelStream().forEach(iotSmsSendDto -> {
			ResponseEntity responseEntity = null;
			HttpHeaders headers = new HttpHeaders();
			headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
//			headers.add("accessToken", accessToken);
			headers.add("accessToken", accessToken);

			HttpEntity<String> requestEntity = new HttpEntity<String>(JSONUtil.toJsonStr(iotSmsSendDto), headers);
			ParameterizedTypeReference<Object> reference = new ParameterizedTypeReference<Object>() {
			};
			String url = "https://scep-api.ctwing.cn:8000/ctwing/smoke3/sms/sendSms";
			URI uri = URI.create(url);
			responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
		});


	}

	/**
	 * 构建短信发送对象
	 *
	 * @param alarm
	 * @return
	 */
	private List<IotSmsSendDto> buildIotSmsSendDto(Alarm alarm) {
		List<IotSmsSendDto> iotSmsSendDtos = new ArrayList<>();

		SmartDevice smartDevice = smartDeviceService.getBaseMapper().selectOne(new QueryWrapper<>(new SmartDevice()).lambda().eq(SmartDevice::getImei, alarm.getDeviceId()));
		Residential residential = residentialService.getById(smartDevice.getResidentialId());
		if (smartDevice != null) {
			//通过设备的类型和所属小区id搜索告警组
			List<AlarmGroup> alarmGroups = alarmGroupService.getBaseMapper().selectList(new QueryWrapper<>(new AlarmGroup()).lambda().eq(AlarmGroup::getResidentialId, smartDevice.getResidentialId()).eq(AlarmGroup::getTag, smartDevice.getDeviceType()));
			if (alarmGroups.size() > 0) {
				//获取告警组中的所有人
				List<AlarmGroupUser> alarmGroupUsers = alarmGroupUserService.getBaseMapper().selectList(new QueryWrapper<>(new AlarmGroupUser()).lambda().eq(AlarmGroupUser::getGroupId, alarmGroups.get(0).getId()));
				for (int i = 0; i < alarmGroupUsers.size(); i++) {
					IotSmsSendDto iotSmsSendDto = new IotSmsSendDto();
					IotSmsTemplateParam iotSmsTemplateParam = new IotSmsTemplateParam();
					iotSmsTemplateParam.setParam1(alarmGroupUsers.get(i).getPerson());//接收人称呼
					String recordTime = alarm.getRecordTime();
					DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
					StringBuffer sb = new StringBuffer();
					try {
						LocalDateTime  parse = LocalDateTime.parse(recordTime,df);
						int year = parse.getYear();
						sb.append(year+"年");
						Month month = parse.getMonth();
						sb.append(month.getValue()+"月");
						int day = parse.getDayOfMonth();
						sb.append(day+"日");
						int hour = parse.getHour();
						sb.append(hour+"时");
						int minutes = parse.getMinute();
						sb.append(minutes+"分");
						int seconds = parse.getSecond();
						sb.append(seconds+"秒");
					} catch (Exception e) {
						e.printStackTrace();
					}

					iotSmsTemplateParam.setParam2(sb.toString());//告警时间
					if (residential != null) {
						iotSmsTemplateParam.setParam3(residential.getName());//小区名称
					} else {
						iotSmsTemplateParam.setParam3("未知小区");//小区名称
					}

					iotSmsTemplateParam.setParam4(smartDevice.getDeviceName());//设备名称
					iotSmsTemplateParam.setParam5(alarm.getAlarmDesc());


					iotSmsSendDto.setTemplate_param(iotSmsTemplateParam);
					iotSmsSendDto.setMobile(alarmGroupUsers.get(i).getPhone());
					iotSmsSendDto.setTemplate_id("91556324");
					iotSmsSendDto.setPrefix("ctwing/smoke3");
					Long timestamp = null;
					try {
						timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(recordTime).getTime();
					} catch (ParseException e) {
						e.printStackTrace();
					}
					iotSmsSendDto.setTimestamp(timestamp.toString());
					iotSmsSendDtos.add(iotSmsSendDto);
				}
			}


		}


		return iotSmsSendDtos;
	}


	private void saveAlarmToRedis(Alarm alarm,String alarmOrgPosition, String tenantId) throws Exception {

		if (alarmOrgPosition != null && alarmOrgPosition.trim() != "") {
			if (tenantId != null) {
				//查询出该租户下所有管理员账号
				List<User> users = userService.getBaseMapper().selectList(new QueryWrapper<>(new User()).lambda().eq(User::getTenantId, tenantId));
				for (int i = 0; i < users.size(); i++) {
					//当前用户
					User user = users.get(i);
					if (isHasPermission(user, alarmOrgPosition)) {//若用户有权限
						String redisKey = "ycwg:alarm:" + user.getId()+":"+alarm.getId();
						redisTemplate.opsForValue().set(redisKey, SerializableUtil.serializeToString(alarm));
					}


				}
			}
		}
	}

	/**
	 * 判断用户账号有没有权限看到该告警记录
	 *
	 * @param user
	 * @param orgPosition
	 * @return
	 */
	private boolean isHasPermission(User user, String orgPosition) {
		boolean flag = false;
		String deptId = user.getDeptId();
		String[] deptIds = deptId.split(",");
		for (int i = 0; i < deptIds.length; i++) {

			OrgPosition orgPosition1 = orgPositionService.getBaseMapper().selectOne(new QueryWrapper<>(new OrgPosition()).lambda().eq(OrgPosition::getOrgId, deptIds[i]));
			if (orgPosition1 != null){
				if(orgPosition.contains(orgPosition1.getOrgPosition())){
					flag = true;
					break;
				}
			}

		}
		return flag;
	}

	@PostMapping("/crmdevice/report")
	public R iotCrmDeviceReport(@RequestBody List<SmartDevice> smartDeviceList) {
		log.debug("crmdeviceReport--->", JSONUtil.toJsonStr(smartDeviceList));
		return R.status(true);
	}
}
