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.studio.admin.generator.service.generator.agent.impl;
  
  import com.alibaba.cloud.ai.studio.admin.generator.service.generator.agent.AbstractAgentTypeProvider;
  import com.alibaba.cloud.ai.studio.admin.generator.service.generator.agent.AgentShell;
  import com.alibaba.cloud.ai.studio.admin.generator.service.generator.agent.CodeSections;
  import com.alibaba.cloud.ai.studio.admin.generator.service.generator.agent.RenderContext;
  import org.springframework.stereotype.Component;
  
  import java.util.List;
  import java.util.Map;
  
  import static com.alibaba.cloud.ai.studio.admin.generator.utils.CodeGenUtils.*;
  
  /**
   * @author yHong
   * @version 1.0
   * @since 2025/8/28 17:57
   */
  @Component
  public class ReactAgentProvider extends AbstractAgentTypeProvider {
  
  	@Override
  	public String type() {
  		return "ReactAgent";
  	}
  
  	@Override
  	public String handleVersion() {
  		return "v1";
  	}
  
  	@Override
  	public String jsonSchema() {
  		// 最小 JSON Schema（可逐步完善）
  		return """
  				{
  				  "$schema": "https://json-schema.org/draft/2020-12/schema",
  				  "title": "ReactAgent Handle",
  				  "type": "object",
  				  "properties": {
  				    "instruction": { "type": "string", "title": "System Instruction" },
  				    "model": {
  				      "type": "object",
  				      "title": "Model Override",
  				      "properties": {
  				        "provider": { "type": "string" },
  				        "name": { "type": "string" },
  				        "options": { "type": "object" },
  				        "chat_client_bean": { "type": "string" }
  				      }
  				    },
  				    "resolver": { "type": "string", "title": "Tool Resolver Bean" },
  				    "tools": { "type": "array", "items": { "type": "string" } },
  				    "max_iterations": { "type": "integer", "minimum": 1, "default": 6 },
  				    "chat_options": { "type": "object" },
  				    "compile_config": { "type": "object" },
  				    "state": {
  				      "type": "object",
  				      "properties": {
  				        "strategies": {
  				          "type": "object",
  				          "additionalProperties": { "type": "string", "enum": ["append", "replace"] }
  				        }
  				      }
  				    },
  				    "hooks": {
  				      "type": "object",
  				      "properties": {
  				        "pre_llm": { "type": "array", "items": { "type": "string" } },
  				        "post_llm": { "type": "array", "items": { "type": "string" } },
  				        "pre_tool": { "type": "array", "items": { "type": "string" } },
  				        "post_tool": { "type": "array", "items": { "type": "string" } }
  				      }
  				    }
  				  }
  				}
  				""";
  	}
  
  	@Override
  	public Map<String, Object> defaultHandle() {
  		return Map.of("instruction", "You are a helpful AI assistant.", "max_iterations", 6, "tools", List.of(),
  				"chat_options", Map.of(), "compile_config", Map.of(), "state",
  				Map.of("strategies", Map.of("messages", "append")));
  	}
  
  	@Override
  	public Map<String, Object> migrate(Map<String, Object> oldHandle, String fromVersion) {
  		// 初版不做迁移
  		return oldHandle;
  	}
  
  	@Override
  	public CodeSections render(AgentShell shell, Map<String, Object> handle, RenderContext ctx,
  			List<String> childVarNames) {
  		String var = ctx.nextVar("reactAgent_");
  
  		// instruction 优先使用壳层
  		String instruction = shell.instruction() != null && !shell.instruction().isBlank() ? shell.instruction()
  				: str(handle.get("instruction"));
  		Integer maxIter = toInt(handle.get("max_iterations"));
  		boolean hasResolver = handle.containsKey("resolver") && str(handle.get("resolver")) != null;
  
  		StringBuilder code = generateBasicBuilderCode("ReactAgent", var, shell);
  
  		// ReactAgent 特有的字段
  		if (shell.inputKeys() != null && !shell.inputKeys().isEmpty()) {
  			// todo: 目前取第一个作为主输入键， 后续计划将多个inputKey通过占位符注入到instruction中
  			String primaryInputKey = shell.inputKeys().get(0);
  			code.append(".inputKey(\"").append(esc(primaryInputKey)).append("\")\n");
  		}
  		code.append(".model(chatModel)\n");
  
  		if (instruction != null && !instruction.isBlank()) {
  			code.append(".instruction(\"").append(esc(instruction)).append("\")\n");
  		}
  		if (maxIter != null && maxIter > 0) {
  			code.append(".maxIterations(").append(maxIter).append(")\n");
  		}
  		if (hasResolver) {
  			code.append(".resolver(toolCallbackResolver)\n");
  		}
  
  		StateStrategyResult stateResult = generateStateStrategyCode(handle, "new AppendStrategy()");
  		code.append(stateResult.code);
  
  		code.append(".build();\n");
  
  		return new CodeSections().imports("import com.alibaba.cloud.ai.graph.CompiledGraph;",
  				"import com.alibaba.cloud.ai.graph.agent.ReactAgent;", "import com.alibaba.cloud.ai.graph.KeyStrategy;",
  				"import com.alibaba.cloud.ai.graph.state.strategy.AppendStrategy;",
  				"import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy;",
  				"import org.springframework.ai.chat.model.ChatModel;",
  				"import org.springframework.context.annotation.Bean;",
  				"import org.springframework.stereotype.Component;",
  				hasResolver ? "import org.springframework.beans.factory.ObjectProvider;" : null,
  				hasResolver ? "import org.springframework.ai.tool.resolution.ToolCallbackResolver;" : null,
  				"import java.util.*;")
  			.code(code.toString())
  			.var(var)
  			.resolver(hasResolver);
  	}
  
  	@Override
  	protected void validateSpecific(Map<String, Object> root) {
  		// ReactAgent 必须有 model 配置
  		Map<String, Object> handle = requireHandle(root);
  
  		if (handle.get("model") == null) {
  			throw new IllegalArgumentException("ReactAgent requires model configuration in handle");
  		}
  
  		// 如果有 tools，检查相关配置
  		if (handle.get("tools") instanceof List<?> tools && !tools.isEmpty()) {
  			// 检查 tools 是否为空字符串
  			for (Object tool : tools) {
  				if (tool instanceof String s && s.trim().isEmpty()) {
  					throw new IllegalArgumentException("ReactAgent tool names cannot be empty");
  				}
  			}
  		}
  
  		// 检查 max_iterations 如果存在，必须是正数
  		Object maxIterations = handle.get("max_iterations");
  		if (maxIterations != null) {
  			requirePositiveNumber(maxIterations, "max_iterations", 1);
  		}
  	}
  
  }
  