package org.springblade.device.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springblade.device.dto.UserInfoDto;
import org.springblade.device.entity.DoorDevice;
import org.springblade.device.service.MsgPublishService;
import org.springblade.device.util.RabbitMqConnectionUtil;
import org.springblade.third.doordevice.entity.InstructPublishLog;
import org.springblade.third.doordevice.entity.MqConf;
import org.springblade.third.doordevice.entity.qinlin.QLinUser;
import org.springblade.third.doordevice.entity.qinlin.QLinUserDevice;
import org.springblade.third.doordevice.feign.IInstructPublishLogClient;
import org.springblade.third.doordevice.feign.IMqConfClient;
import org.springblade.third.doordevice.feign.qinlin.IQLinClient;
import org.springblade.common.constant.Instruct;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created By lidexi in 2021/4/27
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class MsgPublishServiceImpl implements MsgPublishService {

	private final IQLinClient qLinClient;
	private final IMqConfClient mqConfClient;
	private final IInstructPublishLogClient instructPublishLogClient;

	@Override
	public void batchPushInstruct(Object obj, List<DoorDevice> deviceList, Instruct instruct, Map<String, String> map) {
		List<DoorDevice> qinlinList = deviceList.stream().filter(device -> device.getDeviceFactory().equals("qinlin")).collect(Collectors.toList());
		List<DoorDevice> otherList = deviceList.stream().filter(device -> !(device.getDeviceFactory().equals("qinlin"))).collect(Collectors.toList());
		if(qinlinList != null && qinlinList.size() > 0){
			this.qlPushInstruct(obj, qinlinList, instruct);
		}
		otherList.forEach(device -> {
			try {
				this.publish(obj,device,instruct,map);
			}catch (Exception e){
				log.error(e.getMessage(),e);
			}
		});

	}

	@Override
	public void publishJVT(Object obj, String mac, Instruct instruct) {
		MqConf searchEntity = new MqConf();
		searchEntity.setName("巨龙队列");
		MqConf mqConf = this.mqConfClient.detail(searchEntity);
		Connection connection = RabbitMqConnectionUtil.openConnection(mqConf);
		Channel channel = null;
		try {
			//  创建管道
			channel = connection.createChannel();
			//  构建数据
			Map<String,Object> map = new HashMap<>(2);
			map.put("id","10086");
			map.put("code",instruct.getCode());
			map.put("data",obj);
			map.put("serialNumber", mac);
			String msg = JSON.toJSONString(map, SerializerFeature.WriteNonStringValueAsString, SerializerFeature.WriteDateUseDateFormat);
			channel.basicPublish(instruct.getExchangeName(), mac, null, msg.getBytes(StandardCharsets.UTF_8));
		}catch (Exception e){

			}finally {
			//  关闭连接,抛出异常
			RabbitMqConnectionUtil.closeConnection(connection,channel);
		}
	}

	private void qlPushInstruct(Object obj, List<DoorDevice> deviceList, Instruct instruct) {
		String code = instruct.getCode();
		switch (code){
			case "add_user_face":
				UserInfoDto add = BeanUtil.toBean(obj, UserInfoDto.class);
				QLinUser q1 = new QLinUser();
				q1.setUserId(add.getId());
				String deviceIds = deviceList.stream().map(DoorDevice::getSerialNum).collect(Collectors.joining(","));
				q1.setDeviceIds(deviceIds);
				Map<String, Object> map = add.getFaceCodeList().get(0);
				String imgSrc = (String)map.get("imgSrc");
				q1.setFaceUrl(imgSrc);
				Date endDate = add.getEndDate();
				if(endDate != null){
					String strDateFormat = "yyyy-MM-dd HH:mm:ss";
					SimpleDateFormat sdf = new SimpleDateFormat(strDateFormat);
					q1.setExpires(sdf.format(add.getEndDate()));
				}
				this.qLinClient.addUser(q1);
				break;
			case "delete_user":
				UserInfoDto del1 = BeanUtil.toBean(obj, UserInfoDto.class);
				QLinUser q2 = new QLinUser();
				q2.setUserId(del1.getId());
				this.qLinClient.deleteUser(q2);
				break;
			case "delete_user_face":
				UserInfoDto del2 = BeanUtil.toBean(obj, UserInfoDto.class);
				QLinUserDevice q3 = new QLinUserDevice();
				q3.setUserId(del2.getId());
				String deviceIds2 = deviceList.stream().map(DoorDevice::getSerialNum).collect(Collectors.joining(","));
				q3.setDeviceIds(deviceIds2);
				this.qLinClient.deleteUserPermission(q3);
				break;
		}
	}

	@Override
	@SneakyThrows
	public void publish(Object obj, DoorDevice device, Instruct instruct, Map<String,String> m) {
		MqConf searchEntity = new MqConf();
		searchEntity.setId(null);
		MqConf conf = this.mqConfClient.detail(searchEntity);
		if (null == conf){
			throw new Exception("设备未绑定队列");
		}
		//  获取队列连接
		Connection connection = RabbitMqConnectionUtil.openConnection(conf);
		Channel channel = null;
		try {
			//  创建管道
			channel = connection.createChannel();
			long id = IdWorker.getId();
			//  构建数据
			Map<String,Object> map = new HashMap<>(3);
			map.put("id",id);
			map.put("code",instruct.getCode());
			map.put("data",obj);
			map.put("serialNumber",device.getSerialNum());
			String msg = JSON.toJSONString(map, SerializerFeature.WriteNonStringValueAsString, SerializerFeature.WriteDateUseDateFormat);
//            String msg = JsonUtils.objectToJson(map);
			//  推送消息
			channel.basicPublish(instruct.getExchangeName(), device.getSerialNum(), null, msg.getBytes(StandardCharsets.UTF_8));


			//  保存指令推送日志
//            InstructPublishLog publishLog = new InstructPublishLog(id,device, instruct, JsonUtils.objectToJson(obj), m);
			InstructPublishLog publishLog = new InstructPublishLog(id, device, instruct, JSON.toJSONString(obj, SerializerFeature.WriteNonStringValueAsString, SerializerFeature.WriteDateUseDateFormat));
			this.instructPublishLogClient.save(publishLog);
		} finally {
			//  关闭连接,抛出异常
			RabbitMqConnectionUtil.closeConnection(connection,channel);
		}
	}



}
