using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using AxCopilot.Models;

namespace AxCopilot.Services;

public class McpClientService : IDisposable
{
	private readonly McpServerEntry _config;

	private Process? _process;

	private StreamWriter? _writer;

	private StreamReader? _reader;

	private int _requestId;

	internal bool _initialized;

	private readonly List<McpToolDefinition> _tools = new List<McpToolDefinition>();

	private static readonly JsonSerializerOptions _jsonOpts = new JsonSerializerOptions
	{
		PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
		Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
	};

	public string ServerName => _config.Name;

	public bool IsConnected
	{
		get
		{
			Process process = _process;
			return process != null && !process.HasExited;
		}
	}

	public IReadOnlyList<McpToolDefinition> Tools => _tools;

	public McpClientService(McpServerEntry config)
	{
		_config = config;
	}

	public async Task<bool> ConnectAsync(CancellationToken ct = default(CancellationToken))
	{
		try
		{
			if (string.IsNullOrEmpty(_config.Command))
			{
				LogService.Warn("MCP '" + _config.Name + "': command가 비어있습니다.");
				return false;
			}
			ProcessStartInfo psi = new ProcessStartInfo
			{
				FileName = _config.Command,
				UseShellExecute = false,
				RedirectStandardInput = true,
				RedirectStandardOutput = true,
				RedirectStandardError = true,
				CreateNoWindow = true,
				StandardOutputEncoding = Encoding.UTF8,
				StandardErrorEncoding = Encoding.UTF8
			};
			foreach (string arg in _config.Args)
			{
				psi.ArgumentList.Add(arg);
			}
			foreach (var (key, value) in _config.Env)
			{
				psi.Environment[key] = value;
			}
			_process = Process.Start(psi);
			if (_process == null)
			{
				LogService.Warn("MCP '" + _config.Name + "': 프로세스 시작 실패.");
				return false;
			}
			_writer = _process.StandardInput;
			_reader = _process.StandardOutput;
			if (!(await SendRequestAsync("initialize", new
			{
				protocolVersion = "2024-11-05",
				capabilities = new { },
				clientInfo = new
				{
					name = "AX Copilot",
					version = "1.7.2"
				}
			}, ct)).HasValue)
			{
				return false;
			}
			await SendNotificationAsync("notifications/initialized", ct);
			_initialized = true;
			await RefreshToolsAsync(ct);
			LogService.Info($"MCP '{_config.Name}': 연결 성공 ({_tools.Count}개 도구).");
			return true;
		}
		catch (Exception ex)
		{
			Exception ex2 = ex;
			LogService.Warn("MCP '" + _config.Name + "' 연결 실패: " + ex2.Message);
			return false;
		}
	}

	public async Task RefreshToolsAsync(CancellationToken ct = default(CancellationToken))
	{
		_tools.Clear();
		JsonElement? result = await SendRequestAsync("tools/list", new { }, ct);
		if (!result.HasValue)
		{
			return;
		}
		try
		{
			if (!result.Value.TryGetProperty("tools", out var toolsArr))
			{
				return;
			}
			foreach (JsonElement tool in toolsArr.EnumerateArray())
			{
				JsonElement desc;
				McpToolDefinition def = new McpToolDefinition
				{
					Name = (tool.GetProperty("name").GetString() ?? ""),
					Description = (tool.TryGetProperty("description", out desc) ? (desc.GetString() ?? "") : ""),
					ServerName = _config.Name
				};
				if (tool.TryGetProperty("inputSchema", out var schema) && schema.TryGetProperty("properties", out var props))
				{
					foreach (JsonProperty prop in props.EnumerateObject())
					{
						def.Parameters[prop.Name] = new McpParameterDef
						{
							Type = (prop.Value.TryGetProperty("type", out var t) ? (t.GetString() ?? "string") : "string"),
							Description = (prop.Value.TryGetProperty("description", out var d) ? (d.GetString() ?? "") : "")
						};
						t = default(JsonElement);
						d = default(JsonElement);
					}
					if (schema.TryGetProperty("required", out var reqArr))
					{
						foreach (JsonElement item in reqArr.EnumerateArray())
						{
							string reqName = item.GetString();
							if (reqName != null && def.Parameters.TryGetValue(reqName, out McpParameterDef p))
							{
								p.Required = true;
							}
							p = null;
						}
					}
					reqArr = default(JsonElement);
				}
				_tools.Add(def);
				desc = default(JsonElement);
				schema = default(JsonElement);
				props = default(JsonElement);
			}
		}
		catch (Exception ex)
		{
			LogService.Warn("MCP '" + _config.Name + "' 도구 파싱 실패: " + ex.Message);
		}
	}

	public async Task<string> CallToolAsync(string toolName, Dictionary<string, object> arguments, CancellationToken ct = default(CancellationToken))
	{
		JsonElement? result = await SendRequestAsync("tools/call", new
		{
			name = toolName,
			arguments = arguments
		}, ct);
		if (!result.HasValue)
		{
			return "[MCP 호출 실패]";
		}
		try
		{
			if (result.Value.TryGetProperty("content", out var contentArr))
			{
				StringBuilder sb = new StringBuilder();
				foreach (JsonElement item2 in contentArr.EnumerateArray())
				{
					if (item2.TryGetProperty("text", out var text))
					{
						sb.AppendLine(text.GetString());
					}
					text = default(JsonElement);
				}
				return sb.ToString().TrimEnd();
			}
			if (result.Value.TryGetProperty("isError", out var isErr) && isErr.GetBoolean())
			{
				return $"[MCP 오류] {result}";
			}
		}
		catch
		{
		}
		return result?.ToString() ?? "[MCP 빈 응답]";
	}

	private async Task<JsonElement?> SendRequestAsync(string method, object parameters, CancellationToken ct)
	{
		if (_writer == null || _reader == null)
		{
			return null;
		}
		int id = Interlocked.Increment(ref _requestId);
		var request = new
		{
			jsonrpc = "2.0",
			id = id,
			method = method,
			@params = parameters
		};
		string json = JsonSerializer.Serialize(request, _jsonOpts);
		await _writer.WriteLineAsync(json);
		await _writer.FlushAsync();
		using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
		cts.CancelAfter(TimeSpan.FromSeconds(10.0));
		while (!cts.Token.IsCancellationRequested)
		{
			string line = await _reader.ReadLineAsync(cts.Token);
			if (string.IsNullOrWhiteSpace(line))
			{
				continue;
			}
			try
			{
				JsonDocument doc = JsonDocument.Parse(line);
				JsonElement root = doc.RootElement;
				if (root.TryGetProperty("id", out var _))
				{
					if (root.TryGetProperty("result", out var result))
					{
						return result;
					}
					if (root.TryGetProperty("error", out var error))
					{
						LogService.Warn(string.Concat(str3: error.TryGetProperty("message", out var m) ? m.GetString() : "Unknown error", str0: "MCP '", str1: _config.Name, str2: "' RPC 오류: "));
						return null;
					}
					result = default(JsonElement);
					error = default(JsonElement);
				}
			}
			catch
			{
			}
		}
		return null;
	}

	private async Task SendNotificationAsync(string method, CancellationToken ct)
	{
		if (_writer != null)
		{
			var notification = new
			{
				jsonrpc = "2.0",
				method = method
			};
			string json = JsonSerializer.Serialize(notification, _jsonOpts);
			await _writer.WriteLineAsync(json);
			await _writer.FlushAsync();
		}
	}

	public void Dispose()
	{
		try
		{
			_writer?.Dispose();
			_reader?.Dispose();
			Process process = _process;
			if (process != null && !process.HasExited)
			{
				_process.Kill(entireProcessTree: true);
				_process.Dispose();
			}
		}
		catch
		{
		}
	}
}
