package net.yyc.common.rabbitmq.core;

import net.yyc.common.core.entity.BaseMap;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.support.converter.MessageConversionException;
import org.springframework.amqp.support.converter.MessageConverter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Map;

/**
 * Java 原生序列化 MessageConverter，兼容旧包名 BaseMap 消息。
 */
public class JavaSerializationMessageConverter implements MessageConverter {

	private static final byte[] JAVA_SERIALIZATION_MAGIC = new byte[] {(byte) 0xAC, (byte) 0xED};

	@Override
	public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
		if (object == null) {
			throw new MessageConversionException("Cannot convert null to message");
		}
		try {
			com.qunzhixinxi.hnqz.common.core.entity.BaseMap legacyMap = new com.qunzhixinxi.hnqz.common.core.entity.BaseMap();
			if (object instanceof Map) {
				legacyMap.putAll((Map<String, Object>) object);
			} else {
				throw new MessageConversionException("Unsupported message type: " + object.getClass().getName());
			}
			byte[] body = serialize(legacyMap);
			MessageProperties props = messageProperties != null ? messageProperties : new MessageProperties();
			props.setContentType(MessageProperties.CONTENT_TYPE_SERIALIZED_OBJECT);
			return new Message(body, props);
		} catch (IOException e) {
			throw new MessageConversionException("Failed to serialize message", e);
		}
	}

	@Override
	public Object fromMessage(Message message) throws MessageConversionException {
		byte[] body = message.getBody();
		if (body == null || body.length < 2) {
			throw new MessageConversionException("Message body is empty or too short");
		}
		if (!isJavaSerialized(body)) {
			throw new MessageConversionException("Message body is not Java serialized object");
		}
		try {
			Object obj = deserialize(body);
			if (obj instanceof Map) {
				return BaseMap.toBaseMap((Map<String, Object>) obj);
			}
			throw new MessageConversionException("Deserialized object is not a Map: " + obj.getClass().getName());
		} catch (IOException | ClassNotFoundException e) {
			throw new MessageConversionException("Failed to deserialize message", e);
		}
	}

	private static boolean isJavaSerialized(byte[] body) {
		return body[0] == JAVA_SERIALIZATION_MAGIC[0] && body[1] == JAVA_SERIALIZATION_MAGIC[1];
	}

	private static Object deserialize(byte[] body) throws IOException, ClassNotFoundException {
		try (CompatibleObjectInputStream input = new CompatibleObjectInputStream(new ByteArrayInputStream(body))) {
			return input.readObject();
		}
	}

	private static byte[] serialize(Object object) throws IOException {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(output)) {
			objectOutputStream.writeObject(object);
		}
		return output.toByteArray();
	}
}
