package cn.gov.customs.wxjy.ibmmq.service.impl;

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.service.IDataHandlerService;
import cn.gov.customs.wxjy.ibmmq.utils.PackageMappingUtil;
import cn.gov.customs.wxjy.ibmmq.utils.XmlBuildTool;
import com.alibaba.fastjson2.JSONObject;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

/**
 * 数据处理服务实现类
 */
@Slf4j
@AllArgsConstructor
@Service
public class DataHandlerServiceImpl implements IDataHandlerService {


	private ApplicationContext context;
	private JmsTemplate jmsTemplate;
	private MQProperties mqProperties;
	private XmlBuildTool xmlBuildTool;

	@Override
	public <T> void processReceivedDataMessage(DataMessage<T> message) {
		try {
			log.info("接收到数据处理消息：{}", message);

			if (message.getMapperClassName() == null) {
				throw new IllegalArgumentException("参数mapperClassName不能为空");
			}
			if (CollectionUtils.isEmpty(message.getDataList())) {
				throw new IllegalArgumentException("参数dataList不能为空");
			}

			// 动态加载 Mapper 类
			Class<?> mapperClass = Class.forName(PackageMappingUtil.mapMapperPackage(message.getMapperClassName()));
			Object mapper = context.getBean(mapperClass);

			// 确保参数类型不为 null
			Class<?>[] paramTypes = message.getMethodParamTypes();
			if (paramTypes == null || paramTypes.length == 0) {
				// 如果参数类型为 null，尝试推断参数类型
				paramTypes = inferParamTypes(mapperClass, message.getMethodName());
			}

			Method method = null;
			Method[] methods = mapperClass.getMethods();
			for (Method m : methods) {
				if (m.getName().equals(message.getMethodName()) &&
					m.getParameterCount() == paramTypes.length) {
					method = m;
					break;
				}
			}
			if (method == null) {
				throw new NoSuchMethodException("方法未找到: " + message.getMethodName());
			}

			String propertyName = message.getPropertyName();

			// 特殊处理删除操作：直接传递整个dataList作为参数
			if ("deleteBatchIds".equals(message.getMethodName()) && paramTypes.length == 1 && paramTypes[0] == List.class) {
				Object[] params = new Object[]{message.getDataList()};
				method.invoke(mapper, params);
			} else {
				// 执行方法
				for (T data : message.getDataList()) {
					Object[] params = convertToMethodParams(data, method, propertyName);
					method.invoke(mapper, params);
				}
			}

		} catch (Exception e) {
			log.error("数据消息处理失败：", e);
			throw new RuntimeException("处理消息失败，原因：", e);
		}
	}

	@Override
	public <T> void sendDataMessage(DataMessage<T> message) {
		try {
			message.setType(MessageType.DATA);
			// log.info("发送数据同步消息: {}", message);

			// 根据消息来源确定目标队列
			String destinationQueue = getDestinationQueue();

			// 发送消息
			String xmlMsg = xmlBuildTool.generateXmlMsg(JSONObject.toJSONString(message));
			jmsTemplate.convertAndSend(destinationQueue, xmlMsg);
			log.info("消息发送成功：发送队列为：{}，发送消息为： {}", destinationQueue, xmlMsg);
		} catch (Exception e) {
			log.error("发送消息失败: {}", message, e);
			throw new RuntimeException("发送消息失败", e);
		}
	}

	/**
	 * 获取消息目标队列名称
	 *
	 * @return 目标队列名称
	 */
	private String getDestinationQueue() {
		// 根据环境类型确定目标队列。企业端发送到企业端数据队列，管理端发送到管理端数据队列
		if (EnvType.ENTERPRISE.name().equalsIgnoreCase(mqProperties.getEnvType())) {
			return mqProperties.getSendQueue();
		} else {
			return mqProperties.getReceiveQueue();
		}
	}


	/**
	 * 根据数据值获取对应方法参数值
	 * @param data 数据值
	 * @param method 方法
	 * @param propertyName 需提取的属性名称
	 * @return 方法参数值
	 */
	private Object[] convertToMethodParams(Object data, Method method, String propertyName) {
		Class<?>[] paramTypes = method.getParameterTypes();
		String methodName = method.getName();

		// 场景1：无参数方法
		if (paramTypes.length == 0) {
			return new Object[0];
		}

		// 场景2：单参数方法
		if (paramTypes.length == 1) {
			Class<?> paramType = paramTypes[0];

			// 特殊处理删除方法
			if (isDeleteOperation(methodName)) {
				return handleDeleteOperation(data, paramType, methodName, propertyName);
			}

			// 情况1：data是单个对象，且类型匹配
			if (paramType.isInstance(data)) {
				return new Object[]{data};
			}

			// 情况2：参数类型是String，从data中提取指定属性
			if (paramType == String.class && StringUtils.isNotEmpty(propertyName)) {
				String propertyValue = extractPropertyValue(data, propertyName);
				return new Object[]{propertyValue};
			}

			// 情况3：参数类型是String[]，从data中提取指定属性
			if (paramType == String[].class && StringUtils.isNotEmpty(propertyName)) {
				String propertyValue = extractPropertyValue(data, propertyName);
				return new Object[]{new String[]{propertyValue}};
			}

			// 情况4：参数类型是Long，从data中提取指定属性
			if (paramType == Long.class && StringUtils.isNotEmpty(propertyName)) {
				String propertyValue = extractPropertyValue(data, propertyName);
				if (propertyValue != null) {
					return new Object[]{Long.parseLong(propertyValue)};
				}
			}

			// 情况5：参数类型是Long[]，从data中提取指定属性
			if (paramType == Long[].class && StringUtils.isNotEmpty(propertyName)) {
				String propertyValue = extractPropertyValue(data, propertyName);
				if (propertyValue != null) {
					return new Object[]{new Long[]{Long.parseLong(propertyValue)}};
				}
			}

			throw new IllegalArgumentException("不支持的参数类型或数据结构: " +
					data.getClass() + " → " + paramType.getName());
		}

		throw new IllegalArgumentException("仅支持无参或单参数方法");
	}
	// 从对象中提取指定属性的值
	private String extractPropertyValue(Object obj, String propertyName) {
		if (obj == null || propertyName == null) {
			return null;
		}

		BeanWrapper beanWrapper = new BeanWrapperImpl(obj);
		Object value = beanWrapper.getPropertyValue(propertyName);
		return value != null ? value.toString() : null;
	}


	// 推断参数类型的方法
	private Class<?>[] inferParamTypes(Class<?> serviceClass, String methodName) {
		if ("saveOrUpdate".equals(methodName)) {
			// 获取 Service 的泛型类型
			Type[] genericInterfaces = serviceClass.getGenericInterfaces();
			for (Type genericInterface : genericInterfaces) {
				if (genericInterface instanceof ParameterizedType) {
					ParameterizedType pt = (ParameterizedType) genericInterface;
					Type[] actualTypeArguments = pt.getActualTypeArguments();
					if (actualTypeArguments.length > 0) {
						// 返回实体类类型
						return new Class<?>[]{(Class<?>) actualTypeArguments[0]};
					}
				}
			}
		}
		return new Class<?>[0];
	}

	/**
	 * 处理删除操作的特殊参数转换
	 */
	private Object[] handleDeleteOperation(Object data, Class<?> paramType, String methodName, String propertyName) {
		// 如果参数类型是List，直接返回data（data应该是List类型）
		if (paramType == List.class) {
			return new Object[]{data};
		}

		// 如果参数类型是数组，需要特殊处理
		if (paramType.isArray()) {
			Class<?> componentType = paramType.getComponentType();

			// 如果data本身就是List，将其转换为数组
			if (data instanceof List) {
				List<?> dataList = (List<?>) data;
				Object array = Array.newInstance(componentType, dataList.size());
				for (int i = 0; i < dataList.size(); i++) {
					Object element = dataList.get(i);
					if (componentType == Long.class && element instanceof Number) {
						Array.set(array, i, ((Number) element).longValue());
					} else {
						Array.set(array, i, element);
					}
				}
				return new Object[]{array};
			}
			// 如果data是单个值，创建单元素数组
			else {
				Object array = Array.newInstance(componentType, 1);
				if (componentType == Long.class && data instanceof Number) {
					Array.set(array, 0, ((Number) data).longValue());
				} else {
					Array.set(array, 0, data);
				}
				return new Object[]{array};
			}
		}

		// 其他情况，返回data本身
		return new Object[]{data};
	}

	/**
	 * 判断是否为删除操作
	 */
	private boolean isDeleteOperation(String methodName) {
		return methodName != null &&
				(methodName.startsWith("delete") ||
						methodName.startsWith("remove") ||
						"deleteByPks".equals(methodName) ||
						"deleteBatchIds".equals(methodName));
	}
}
