package cn.gov.customs.wxjy.ibmmq.listener;//package cn.gov.customs.zhsj.ibmmq.listener;

import cn.gov.customs.wxjy.ibmmq.config.MQProperties;
import cn.gov.customs.wxjy.ibmmq.enums.EnvType;
import cn.gov.customs.wxjy.ibmmq.enums.MessageType;
import cn.gov.customs.wxjy.ibmmq.model.DataMessage;
import cn.gov.customs.wxjy.ibmmq.model.DxpMsg;
import cn.gov.customs.wxjy.ibmmq.model.FileMessage;
import cn.gov.customs.wxjy.ibmmq.service.IDataHandlerService;
import cn.gov.customs.wxjy.ibmmq.service.IFileHandlerService;
import cn.gov.customs.wxjy.ibmmq.utils.PackageMappingUtil;
import cn.gov.customs.wxjy.ibmmq.utils.XmlBuildTool;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader;
import com.ibm.msg.client.wmq.WMQConstants;
import jodd.util.StringUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jms.annotation.JmsListenerConfigurer;
import org.springframework.jms.config.JmsListenerEndpointRegistrar;
import org.springframework.jms.config.SimpleJmsListenerEndpoint;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

import javax.jms.BytesMessage;
import javax.jms.ObjectMessage;
import javax.jms.TextMessage;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;

/**
 * MQ 消息监听器
 * 通过配置文件中的app.env.type属性，动态注册监听器
 */

@Component
@AllArgsConstructor
@Slf4j
public class MQMessageListener implements JmsListenerConfigurer {

	private IDataHandlerService dataHandlerService;
	private IFileHandlerService fileHandlerService;
	private MQProperties mqProperties;
	private XmlBuildTool xmlBuildTool;


	/**
	 * 处理管理端文件传输消息
	 *
	 * @param fileMessage 文件传输消息
	 */
	public void processMgrFileMessage(FileMessage fileMessage) {
		log.warn("企业端监听到管理端文件队列消息: {}", fileMessage);
		fileHandlerService.processReceivedFileMessage(fileMessage);
	}

	/**
	 * 处理企业端文件传输消息
	 *
	 * @param fileMessage 文件传输消息
	 */
	public void processEntFileMessage(FileMessage fileMessage) {
		log.warn("管理端监听到企业端文件队列消息: {}", fileMessage);
		fileHandlerService.processReceivedFileMessage(fileMessage);
	}

	/**
	 * 处理管理端数据传输消息
	 *
	 * @param dataMessage 数据传输消息
	 */
	public void processMgrDataMessage(DataMessage<?> dataMessage) {
		log.warn("企业端监听到管理端数据队列消息: {}", dataMessage);
		dataHandlerService.processReceivedDataMessage(dataMessage);
	}

	/**
	 * 处理企业端数据传输消息
	 *
	 * @param dataMessage 数据传输消息
	 */
	public void processEntDataMessage(DataMessage<?> dataMessage) {
		log.warn("管理端监听到企业端数据队列消息: {}", dataMessage);
		dataHandlerService.processReceivedDataMessage(dataMessage);
	}

	@Override
	public void configureJmsListeners(@NonNull JmsListenerEndpointRegistrar registrar) {
		log.debug("registrar:"+ JSON.toJSONString(registrar));
		String envType = mqProperties.getEnvType();
		if (EnvType.ENTERPRISE.name().equalsIgnoreCase(envType)) {
			// 企业端监听接收消息队列
			registerListener(registrar, mqProperties.getReceiveQueue(), message -> {
				if (message instanceof FileMessage) {
					processMgrFileMessage((FileMessage) message);
				} else if (message instanceof DataMessage) {
					processMgrDataMessage((DataMessage<?>) message);
				} else {
					log.error("未知的消息类型: {}", message);
				}
			});
		} else if (EnvType.MANAGEMENT.name().equalsIgnoreCase(envType)) {
			// 管理端监听发送消息队列

			registerListener(registrar, mqProperties.getSendQueue(), message -> {
				log.debug("message:"+JSON.toJSONString(message));
				if (message instanceof FileMessage) {
					processEntFileMessage((FileMessage) message);
				} else if (message instanceof DataMessage) {
					processEntDataMessage((DataMessage<?>) message);
				} else {
					log.error("未知的消息类型: {}", message);
				}
			});
		}
	}

	private void registerListener(JmsListenerEndpointRegistrar registrar, String destination, MessageProcessor processor) {
		SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
		endpoint.setId(destination + "-listener");
		endpoint.setDestination(destination);
		endpoint.setMessageListener(message -> {
			try {
				String decodedString;
				if (message instanceof BytesMessage) {
					BytesMessage bytesMessage = (BytesMessage) message;
					int TEXT_LENGTH = new Long(bytesMessage.getBodyLength()).intValue();
					byte[] bytes = new byte[TEXT_LENGTH];
					bytesMessage.readBytes(bytes, TEXT_LENGTH);
					String codePage = message.getStringProperty(WMQConstants.JMS_IBM_CHARACTER_SET);
					String textContent = new String(bytes, codePage);
					log.warn("[{}]队列收到字符串消息: {}", destination, textContent);
					// 解析XML消息
					DxpMsg dxpMsg = xmlBuildTool.parseXmlToDxpMsg(textContent);
					String data = dxpMsg.getData();
					Base64.Decoder decoder = Base64.getDecoder();
					byte[] decode = decoder.decode(data);
					decodedString = new String(decode);
				} else if (message instanceof TextMessage) {
					TextMessage textMessage = (TextMessage) message;
					String textContent = textMessage.getText();
					log.warn("[{}]队列收到字符串消息: {}", destination, textContent);
					// 解析XML消息
					DxpMsg dxpMsg = xmlBuildTool.parseXmlToDxpMsg(textContent);
					String data = dxpMsg.getData();
					Base64.Decoder decoder = Base64.getDecoder();
					byte[] decode = decoder.decode(data);
					decodedString = new String(decode);
				} else if (message instanceof ObjectMessage) {
					ObjectMessage objectMessage = (ObjectMessage) message;
					Object payload = objectMessage.getObject();
					log.warn("[{}]队列收到对象消息: {}", destination, payload);
					// 解析XML消息
					DxpMsg dxpMsg = xmlBuildTool.parseXmlToDxpMsg(payload.toString());
					String data = dxpMsg.getData();
					Base64.Decoder decoder = Base64.getDecoder();
					byte[] decode = decoder.decode(data);
					decodedString = new String(decode);
				} else {
					log.error("[{}]队列收到未知的消息类型: {}", destination, message);
					return;
				}
				// 判断消息类型并转换为相应对象
				Object messageObject = convertStringToObject(decodedString);
				if (messageObject != null) {
					processor.processMessage(messageObject);
				} else {
					log.error("无法识别的消息格式: {}", decodedString);
				}
			} catch (Exception e) {
				log.error("处理消息失败: {}", message, e);
			}
		});
		registrar.registerEndpoint(endpoint);
		log.warn("[{}]队列监听器启动成功", destination);
	}

	// 将字符串转换为相应的对象
	private Object convertStringToObject(String jsonString) throws Exception {
		JSONObject jsonObject = JSONObject.parseObject(jsonString);
		String type = jsonObject.getString("type");
		if (type == null) {
			return null;
		}
		MessageType messageType = MessageType.valueOf(type.toUpperCase());
		switch (messageType) {
			case SHARD:
			case COMPLETE:
				return jsonObject.toJavaObject(FileMessage.class);
			case DATA:
				return dataMessageDeserialize(jsonObject);
			// 可继续添加其他类型
			default:
				log.warn("未知的消息类型: {}", type);
				return null;
		}
	}

	@FunctionalInterface
	private interface MessageProcessor {
		void processMessage(Object message);
	}

	private DataMessage<?> dataMessageDeserialize(JSONObject jsonObject) throws Exception {
		// 1. 从JSON中获取methodParamTypes，确定dataList的元素类型
		String[] paramTypeNames = jsonObject.getObject("methodParamTypes", String[].class);
		String methodName = jsonObject.getString("methodName");
		String elementTypeName;
		Class<?>[] paramTypes = null;

		if (paramTypeNames == null || paramTypeNames.length == 0) {
			throw new IllegalArgumentException("methodParamTypes不能为空");
		} else {
			elementTypeName = paramTypeNames[0];
			// 转换所有参数类型
			paramTypes = new Class<?>[paramTypeNames.length];
			for (int i = 0; i < paramTypeNames.length; i++) {
				if (!StringUtil.isEmpty(paramTypeNames[i])) {
					// 先进行包名映射，再加载类
					String mappedClassName = PackageMappingUtil.mapEntityPackage(paramTypeNames[i]);
					paramTypes[i] = Class.forName(mappedClassName);
				}
			}
		}

		// 特殊处理删除方法：如果方法是deleteBatchIds且参数类型是List，则dataList元素类型为Long
		Class<?> elementType;
		if ("deleteByPks".equals(methodName) && "java.util.List".equals(elementTypeName)) {
			elementType = Long.class;
		} else if (StringUtil.isEmpty(elementTypeName)) {
			throw new IllegalArgumentException("实体类型获取失败！");
		} else {
			// 包名映射：将发送端包名映射到接收端包名
			String mappedElementTypeName = PackageMappingUtil.mapEntityPackage(elementTypeName);
			elementType = Class.forName(mappedElementTypeName);
		}

		// 2. 在反序列化之前，修改JSON中的类名
		String jsonString = jsonObject.toString();
		// 替换所有原始类名为映射后的类名
		for (int i = 0; i < paramTypeNames.length; i++) {
			if (!StringUtil.isEmpty(paramTypeNames[i])) {
				String mappedName = PackageMappingUtil.mapEntityPackage(paramTypeNames[i]);
				jsonString = jsonString.replace(paramTypeNames[i], mappedName);
			}
		}

		// 3. 动态构建DataMessage<T>的泛型类型
		Type dataMessageType = new ParameterizedType() {
			@Override
			public Type[] getActualTypeArguments() {
				return new Type[]{elementType};
			}

			@Override
			public Type getRawType() {
				return DataMessage.class;
			}

			@Override
			public Type getOwnerType() {
				return null;
			}
		};

		// 4. 使用修改后的JSON字符串反序列化
		DataMessage<?> dataMessage = JSON.parseObject(
				jsonString,
				dataMessageType,
				JSONReader.Feature.SupportClassForName
		);

		// 5. 手动设置参数类型数组
		if (paramTypes != null) {
			Field methodParamTypesField = DataMessage.class.getDeclaredField("methodParamTypes");
			methodParamTypesField.setAccessible(true);
			methodParamTypesField.set(dataMessage, paramTypes);
		}

		return customDataMessageDeserialize(jsonObject, elementType, paramTypes);
	}

	private DataMessage<?> customDataMessageDeserialize(JSONObject jsonObject, Class<?> elementType, Class<?>[] paramTypes) throws Exception {
		// 创建 DataMessage 实例
		DataMessage<Object> dataMessage = new DataMessage<>();

		// 设置基本字段
		dataMessage.setMsgId(jsonObject.getString("msgId"));
		dataMessage.setSendTime(jsonObject.getDate("sendTime"));
		dataMessage.setType(MessageType.valueOf(jsonObject.getString("type")));
		dataMessage.setMethodName(jsonObject.getString("methodName"));
		dataMessage.setMapperClassName(PackageMappingUtil.mapMapperPackage(jsonObject.getString("mapperClassName")));

		// 设置参数类型
		Field methodParamTypesField = DataMessage.class.getDeclaredField("methodParamTypes");
		methodParamTypesField.setAccessible(true);
		methodParamTypesField.set(dataMessage, paramTypes);

		// 处理 dataList - 针对删除操作优化
		JSONArray dataListArray = jsonObject.getJSONArray("dataList");
		if (dataListArray != null) {
			List<Object> convertedList = new ArrayList<>();

			// 判断是否为删除操作
			boolean isDeleteOperation = "deleteByPks".equals(dataMessage.getMethodName())
					|| "deleteBatchIds".equals(dataMessage.getMethodName());

			if (isDeleteOperation && elementType == Long.class) {
				// 删除操作：直接解析为Long，不需要字段映射
				for (int i = 0; i < dataListArray.size(); i++) {
					Object item = dataListArray.get(i);
					if (item instanceof Number) {
						convertedList.add(((Number) item).longValue());
					} else if (item instanceof String) {
						convertedList.add(Long.parseLong((String) item));
					} else {
						log.warn("删除操作中的dataList元素类型不支持: {}", item.getClass());
						convertedList.add(item);
					}
				}
			} else {
				// 非删除操作：使用原有的字段映射逻辑
				Map<String, String> fieldMapping = PackageMappingUtil.getFieldMapping(elementType.getName());

				for (int i = 0; i < dataListArray.size(); i++) {
					JSONObject item = dataListArray.getJSONObject(i);

					// 应用字段映射
					if (fieldMapping != null) {
						for (Map.Entry<String, String> entry : fieldMapping.entrySet()) {
							if (item.containsKey(entry.getKey())) {
								Object value = item.get(entry.getKey());
								item.put(entry.getValue(), value);
								item.remove(entry.getKey());
							}
						}
					}

					// 转换为目标对象
					Object convertedItem = JSON.parseObject(item.toString(), elementType);
					convertedList.add(convertedItem);
				}
			}

			// 使用反射设置 dataList
			Field dataListField = DataMessage.class.getDeclaredField("dataList");
			dataListField.setAccessible(true);
			dataListField.set(dataMessage, convertedList);
		}

		return dataMessage;
	}

}
