using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AxCopilot.Models;

namespace AxCopilot.Services.Agent;

public class ToolRegistry : IDisposable
{
	private readonly Dictionary<string, IAgentTool> _tools = new Dictionary<string, IAgentTool>(StringComparer.OrdinalIgnoreCase);

	private readonly List<IDisposable> _ownedResources = new List<IDisposable>();

	public IReadOnlyCollection<IAgentTool> All => _tools.Values;

	public IAgentTool? Get(string name)
	{
		IAgentTool value;
		return _tools.TryGetValue(name, out value) ? value : null;
	}

	public void Register(IAgentTool tool)
	{
		_tools[tool.Name] = tool;
	}

	public async Task<int> RegisterMcpToolsAsync(IEnumerable<McpServerEntry>? servers, CancellationToken ct = default(CancellationToken))
	{
		if (servers == null)
		{
			return 0;
		}
		int registered = 0;
		foreach (McpServerEntry server in servers)
		{
			if (server == null || !server.Enabled)
			{
				continue;
			}
			if (!string.Equals(server.Transport, "stdio", StringComparison.OrdinalIgnoreCase))
			{
				LogService.Warn($"MCP '{server.Name}': unsupported transport '{server.Transport}'.");
				continue;
			}
			McpClientService client = new McpClientService(server);
			if (!(await client.ConnectAsync(ct).ConfigureAwait(continueOnCapturedContext: false)))
			{
				client.Dispose();
				continue;
			}
			_ownedResources.Add(client);
			foreach (McpToolDefinition def in client.Tools)
			{
				Register(new McpTool(client, def));
				registered++;
			}
		}
		return registered;
	}

	public IReadOnlyCollection<IAgentTool> GetActiveTools(IEnumerable<string>? disabledNames = null)
	{
		if (disabledNames == null)
		{
			return All;
		}
		HashSet<string> disabled = new HashSet<string>(disabledNames, StringComparer.OrdinalIgnoreCase);
		if (disabled.Count == 0)
		{
			return All;
		}
		return _tools.Values.Where((IAgentTool t) => !disabled.Contains(t.Name)).ToList().AsReadOnly();
	}

	public void Dispose()
	{
		foreach (IAgentTool value in _tools.Values)
		{
			if (value is IDisposable disposable)
			{
				disposable.Dispose();
			}
		}
		foreach (IDisposable ownedResource in _ownedResources)
		{
			ownedResource.Dispose();
		}
		_ownedResources.Clear();
		_tools.Clear();
	}

	public static ToolRegistry CreateDefault()
	{
		ToolRegistry toolRegistry = new ToolRegistry();
		toolRegistry.Register(new FileReadTool());
		toolRegistry.Register(new FileWriteTool());
		toolRegistry.Register(new FileEditTool());
		toolRegistry.Register(new GlobTool());
		toolRegistry.Register(new GrepTool());
		toolRegistry.Register(new ProcessTool());
		toolRegistry.Register(new FolderMapTool());
		toolRegistry.Register(new DocumentReaderTool());
		toolRegistry.Register(new ExcelSkill());
		toolRegistry.Register(new DocxSkill());
		toolRegistry.Register(new CsvSkill());
		toolRegistry.Register(new MarkdownSkill());
		toolRegistry.Register(new HtmlSkill());
		toolRegistry.Register(new ChartSkill());
		toolRegistry.Register(new BatchSkill());
		toolRegistry.Register(new PptxSkill());
		toolRegistry.Register(new DocumentPlannerTool());
		toolRegistry.Register(new DocumentAssemblerTool());
		toolRegistry.Register(new DocumentReviewTool());
		toolRegistry.Register(new FormatConvertTool());
		toolRegistry.Register(new DevEnvDetectTool());
		toolRegistry.Register(new BuildRunTool());
		toolRegistry.Register(new GitTool());
		toolRegistry.Register(new LspTool());
		toolRegistry.Register(new SubAgentTool());
		toolRegistry.Register(new WaitAgentsTool());
		toolRegistry.Register(new CodeSearchTool());
		toolRegistry.Register(new TestLoopTool());
		toolRegistry.Register(new CodeReviewTool());
		toolRegistry.Register(new ProjectRuleTool());
		toolRegistry.Register(new SkillManagerTool());
		toolRegistry.Register(new MemoryTool());
		toolRegistry.Register(new JsonTool());
		toolRegistry.Register(new RegexTool());
		toolRegistry.Register(new DiffTool());
		toolRegistry.Register(new ClipboardTool());
		toolRegistry.Register(new NotifyTool());
		toolRegistry.Register(new EnvTool());
		toolRegistry.Register(new ZipTool());
		toolRegistry.Register(new HttpTool());
		toolRegistry.Register(new SqlTool());
		toolRegistry.Register(new Base64Tool());
		toolRegistry.Register(new HashTool());
		toolRegistry.Register(new DateTimeTool());
		toolRegistry.Register(new SnippetRunnerTool());
		toolRegistry.Register(new DataPivotTool());
		toolRegistry.Register(new TemplateRenderTool());
		toolRegistry.Register(new TextSummarizeTool());
		toolRegistry.Register(new FileWatchTool());
		toolRegistry.Register(new ImageAnalyzeTool());
		toolRegistry.Register(new FileManageTool());
		toolRegistry.Register(new FileInfoTool());
		toolRegistry.Register(new MultiReadTool());
		toolRegistry.Register(new UserAskTool());
		toolRegistry.Register(new OpenExternalTool());
		toolRegistry.Register(new MathTool());
		toolRegistry.Register(new XmlTool());
		toolRegistry.Register(new EncodingTool());
		toolRegistry.Register(new TaskTrackerTool());
		toolRegistry.Register(new SuggestActionsTool());
		toolRegistry.Register(new DiffPreviewTool());
		toolRegistry.Register(new CheckpointTool());
		toolRegistry.Register(new PlaybookTool());
		return toolRegistry;
	}
}
