content: /*
   * Copyright 2024-2025 the original author or authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      https://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.alibaba.cloud.ai.agent.nacos.utils;
  
  import java.lang.reflect.Method;
  import java.util.HashMap;
  import java.util.Map;
  
  import com.alibaba.cloud.ai.observation.model.ObservationMetadataAwareOptions;
  import net.sf.cglib.proxy.Enhancer;
  import net.sf.cglib.proxy.MethodInterceptor;
  import net.sf.cglib.proxy.MethodProxy;
  
  import org.springframework.ai.chat.prompt.ChatOptions;
  
  /**
   * 基于CGLIB的动态代理工厂
   * 通过创建子类的方式实现多接口功能
   */
  public class CglibProxyFactory {
  
  	/**
  	 * 创建同时实现ChatOptions和ObservationMetadataAwareOptions接口的代理对象
  	 *
  	 * @param chatOptions 原始的ChatOptions对象
  	 * @param initialMetadata 初始的观察元数据
  	 * @return 代理对象，同时实现了ChatOptions和ObservationMetadataAwareOptions接口
  	 */
  	public static Object createProxy(ChatOptions chatOptions, Map<String, String> initialMetadata) {
  		// 创建CGLIB增强器
  		Enhancer enhancer = new Enhancer();
  
  		// 设置父类为ChatOptionsImpl
  		enhancer.setSuperclass(chatOptions.getClass());
  
  		// 设置要实现的接口
  		enhancer.setInterfaces(new Class[] {ChatOptions.class, ObservationMetadataAwareOptions.class});
  
  		// 设置回调处理器
  		enhancer.setCallback(new CglibMethodInterceptor(chatOptions, initialMetadata));
  
  		// 创建代理对象
  		return enhancer.create();
  	}
  
  	/**
  	 * CGLIB方法拦截器
  	 */
  	private static class CglibMethodInterceptor implements MethodInterceptor {
  
  		private final ChatOptions chatOptions;
  		private final Map<String, String> observationMetadata;
  		private String observationName;
  		private Boolean observationEnabled;
  
  		public CglibMethodInterceptor(ChatOptions chatOptions, Map<String, String> initialMetadata) {
  			this.chatOptions = chatOptions;
  			this.observationMetadata = new HashMap<>(initialMetadata);
  			this.observationName = "ChatObservation";
  			this.observationEnabled = true;
  		}
  
  		@Override
  		public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  			String methodName = method.getName();
  			Class<?> declaringClass = method.getDeclaringClass();
  
  			// 1. 拦截 copy()
  			if (isCopyMethod(method)) {
  				return createCopiedProxy();
  			}
  
  			// 处理ChatOptions接口的方法 - 直接转发到原始对象
  			if (declaringClass == ChatOptions.class) {
  				return method.invoke(chatOptions, args);
  			}
  
  			// 处理ObservationMetadataAwareOptions接口的方法
  			if (declaringClass == ObservationMetadataAwareOptions.class) {
  				return handleObservationMethod(methodName, args);
  			}
  
  			// 处理Object类的方法
  			if (declaringClass == Object.class) {
  				return handleObjectMethod(methodName, args, obj);
  			}
  
  			// 处理父类方法 - 转发到原始对象
  			return method.invoke(chatOptions, args);
  		}
  
  		private boolean isCopyMethod(Method method) {
  			return "copy".equals(method.getName())
  					&& method.getParameterCount() == 0
  					&& ChatOptions.class.isAssignableFrom(method.getReturnType());
  		}
  
  		private Object createCopiedProxy() {
  			ChatOptions copiedChatOptions;
  			try {
  				Method copyMethod = chatOptions.getClass().getMethod("copy");
  				// 如果是 private 或 protected，需要 setAccessible(true)
  				copyMethod.setAccessible(true);
  				Object result = copyMethod.invoke(chatOptions);
  				if (!(result instanceof ChatOptions)) {
  					throw new IllegalStateException("copy() method did not return a ChatOptions instance");
  				}
  				copiedChatOptions = (ChatOptions) result;
  			}
  			catch (NoSuchMethodException e) {
  				throw new IllegalStateException("ChatOptions implementation missing copy() method", e);
  			}
  			catch (Exception e) {
  				throw new RuntimeException("Failed to invoke copy() method", e);
  			}
  
  			// 创建新的代理对象（深拷贝 metadata）
  			return CglibProxyFactory.createProxy(
  					copiedChatOptions,
  					new HashMap<>(this.observationMetadata)
  			);
  		}
  
  		/**
  		 * 处理观察方法 - 基于方法名动态处理
  		 */
  		private Object handleObservationMethod(String methodName, Object[] args) {
  			switch (methodName) {
  			case "getObservationMetadata":
  				return observationMetadata;
  
  			case "setObservationMetadata":
  				if (args != null && args.length > 0 && args[0] instanceof Map) {
  					observationMetadata.clear();
  					observationMetadata.putAll((Map<String, String>) args[0]);
  				}
  				return null;
  
  			case "addObservationMetadata":
  				if (args != null && args.length >= 2) {
  					observationMetadata.put((String) args[0], (String) args[1]);
  				}
  				return null;
  
  			case "getObservationName":
  				return observationName;
  
  			case "setObservationName":
  				if (args != null && args.length > 0) {
  					observationName = (String) args[0];
  				}
  				return null;
  
  			case "isObservationEnabled":
  				return observationEnabled;
  
  			case "setObservationEnabled":
  				if (args != null && args.length > 0) {
  					observationEnabled = (Boolean) args[0];
  				}
  				return null;
  
  			default:
  				throw new UnsupportedOperationException("Unknown observation method: " + methodName);
  			}
  		}
  
  		/**
  		 * 处理Object类的方法
  		 */
  		private Object handleObjectMethod(String methodName, Object[] args, Object obj) {
  			switch (methodName) {
  			case "toString":
  				return "CglibProxy{" +
  						"chatOptions=" + chatOptions +
  						", observationMetadata=" + observationMetadata +
  						", observationName='" + observationName + '\'' +
  						", observationEnabled=" + observationEnabled +
  						'}';
  
  			case "equals":
  				if (args != null && args.length > 0) {
  					return obj == args[0];
  				}
  				return false;
  
  			case "hashCode":
  				return System.identityHashCode(obj);
  
  			default:
  				throw new UnsupportedOperationException("Unknown Object method: " + methodName);
  			}
  		}
  	}
  }
  