using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace AxCopilot.Services.Agent;

public class PlaybookTool : IAgentTool
{
	private class PlaybookData
	{
		public int Id { get; set; }

		public string Name { get; set; } = "";

		public string Description { get; set; } = "";

		public List<string> Steps { get; set; } = new List<string>();

		public List<string> ToolsUsed { get; set; } = new List<string>();

		public string CreatedAt { get; set; } = "";
	}

	public string Name => "playbook";

	public string Description => "Save, list, describe, or delete execution playbooks. A playbook captures a successful task workflow for reuse.\n- action=\"save\": Save a new playbook (name, description, steps required)\n- action=\"list\": List all saved playbooks\n- action=\"describe\": Show full playbook details (id required)\n- action=\"delete\": Delete a playbook (id required)";

	public ToolParameterSchema Parameters
	{
		get
		{
			ToolParameterSchema toolParameterSchema = new ToolParameterSchema();
			Dictionary<string, ToolProperty> dictionary = new Dictionary<string, ToolProperty>();
			ToolProperty obj = new ToolProperty
			{
				Type = "string",
				Description = "save | list | describe | delete"
			};
			int num = 4;
			List<string> list = new List<string>(num);
			CollectionsMarshal.SetCount(list, num);
			Span<string> span = CollectionsMarshal.AsSpan(list);
			span[0] = "save";
			span[1] = "list";
			span[2] = "describe";
			span[3] = "delete";
			obj.Enum = list;
			dictionary["action"] = obj;
			dictionary["name"] = new ToolProperty
			{
				Type = "string",
				Description = "Playbook name (for save)"
			};
			dictionary["description"] = new ToolProperty
			{
				Type = "string",
				Description = "What this playbook does (for save)"
			};
			dictionary["steps"] = new ToolProperty
			{
				Type = "array",
				Description = "List of step descriptions (for save)",
				Items = new ToolProperty
				{
					Type = "string",
					Description = "Step description"
				}
			};
			dictionary["tools_used"] = new ToolProperty
			{
				Type = "array",
				Description = "List of tool names used in this workflow (for save)",
				Items = new ToolProperty
				{
					Type = "string",
					Description = "Tool name"
				}
			};
			dictionary["id"] = new ToolProperty
			{
				Type = "integer",
				Description = "Playbook ID (for describe/delete)"
			};
			toolParameterSchema.Properties = dictionary;
			num = 1;
			List<string> list2 = new List<string>(num);
			CollectionsMarshal.SetCount(list2, num);
			CollectionsMarshal.AsSpan(list2)[0] = "action";
			toolParameterSchema.Required = list2;
			return toolParameterSchema;
		}
	}

	public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken))
	{
		if (!args.TryGetProperty("action", out var actionEl))
		{
			return ToolResult.Fail("action이 필요합니다.");
		}
		string action = actionEl.GetString() ?? "";
		if (string.IsNullOrEmpty(context.WorkFolder))
		{
			return ToolResult.Fail("작업 폴더가 설정되지 않았습니다.");
		}
		string playbookDir = Path.Combine(context.WorkFolder, ".ax", "playbooks");
		if (1 == 0)
		{
		}
		ToolResult result = action switch
		{
			"save" => await SavePlaybook(args, playbookDir, ct), 
			"list" => ListPlaybooks(playbookDir), 
			"describe" => await DescribePlaybook(args, playbookDir, ct), 
			"delete" => DeletePlaybook(args, playbookDir), 
			_ => ToolResult.Fail("알 수 없는 액션: " + action + ". save | list | describe | delete 중 선택하세요."), 
		};
		if (1 == 0)
		{
		}
		return result;
	}

	private static async Task<ToolResult> SavePlaybook(JsonElement args, string playbookDir, CancellationToken ct)
	{
		JsonElement n;
		string name = (args.TryGetProperty("name", out n) ? (n.GetString() ?? "") : "");
		JsonElement d;
		string description = (args.TryGetProperty("description", out d) ? (d.GetString() ?? "") : "");
		if (string.IsNullOrWhiteSpace(name))
		{
			return ToolResult.Fail("플레이북 name이 필요합니다.");
		}
		if (string.IsNullOrWhiteSpace(description))
		{
			return ToolResult.Fail("플레이북 description이 필요합니다.");
		}
		List<string> steps = new List<string>();
		if (args.TryGetProperty("steps", out var stepsEl) && stepsEl.ValueKind == JsonValueKind.Array)
		{
			foreach (JsonElement item in stepsEl.EnumerateArray())
			{
				string s = item.GetString();
				if (!string.IsNullOrWhiteSpace(s))
				{
					steps.Add(s);
				}
			}
		}
		if (steps.Count == 0)
		{
			return ToolResult.Fail("최소 1개 이상의 step이 필요합니다.");
		}
		List<string> toolsUsed = new List<string>();
		if (args.TryGetProperty("tools_used", out var toolsEl) && toolsEl.ValueKind == JsonValueKind.Array)
		{
			foreach (JsonElement item2 in toolsEl.EnumerateArray())
			{
				string t = item2.GetString();
				if (!string.IsNullOrWhiteSpace(t))
				{
					toolsUsed.Add(t);
				}
			}
		}
		try
		{
			Directory.CreateDirectory(playbookDir);
			int nextId = GetNextId(playbookDir);
			string safeName = string.Join("_", name.Split(Path.GetInvalidFileNameChars()));
			string fileName = $"{nextId}_{safeName}.json";
			PlaybookData playbook = new PlaybookData
			{
				Id = nextId,
				Name = name,
				Description = description,
				Steps = steps,
				ToolsUsed = toolsUsed,
				CreatedAt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
			};
			string json = JsonSerializer.Serialize(playbook, new JsonSerializerOptions
			{
				WriteIndented = true,
				Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
			});
			string filePath = Path.Combine(playbookDir, fileName);
			await File.WriteAllTextAsync(filePath, json, ct);
			return ToolResult.Ok($"플레이북 저장 완료: [{nextId}] {name}\n단계 수: {steps.Count}, 사용 도구: {toolsUsed.Count}개");
		}
		catch (Exception ex)
		{
			return ToolResult.Fail("플레이북 저장 오류: " + ex.Message);
		}
	}

	private static ToolResult ListPlaybooks(string playbookDir)
	{
		if (!Directory.Exists(playbookDir))
		{
			return ToolResult.Ok("저장된 플레이북이 없습니다.");
		}
		List<string> list = (from f in Directory.GetFiles(playbookDir, "*.json")
			orderby f
			select f).ToList();
		if (list.Count == 0)
		{
			return ToolResult.Ok("저장된 플레이북이 없습니다.");
		}
		StringBuilder stringBuilder = new StringBuilder();
		StringBuilder stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder3 = stringBuilder2;
		StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(7, 1, stringBuilder2);
		handler.AppendLiteral("플레이북 ");
		handler.AppendFormatted(list.Count);
		handler.AppendLiteral("개:");
		stringBuilder3.AppendLine(ref handler);
		foreach (string item in list)
		{
			try
			{
				string json = File.ReadAllText(item);
				PlaybookData playbookData = JsonSerializer.Deserialize<PlaybookData>(json);
				if (playbookData != null)
				{
					stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder4 = stringBuilder2;
					handler = new StringBuilder.AppendInterpolatedStringHandler(15, 5, stringBuilder2);
					handler.AppendLiteral("  [");
					handler.AppendFormatted(playbookData.Id);
					handler.AppendLiteral("] ");
					handler.AppendFormatted(playbookData.Name);
					handler.AppendLiteral(" — ");
					handler.AppendFormatted(playbookData.Description);
					handler.AppendLiteral(" (");
					handler.AppendFormatted(playbookData.Steps.Count);
					handler.AppendLiteral("단계, ");
					handler.AppendFormatted(playbookData.CreatedAt);
					handler.AppendLiteral(")");
					stringBuilder4.AppendLine(ref handler);
				}
			}
			catch
			{
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder5 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(14, 1, stringBuilder2);
				handler.AppendLiteral("  [?] ");
				handler.AppendFormatted(Path.GetFileName(item));
				handler.AppendLiteral(" — 파싱 오류");
				stringBuilder5.AppendLine(ref handler);
			}
		}
		return ToolResult.Ok(stringBuilder.ToString());
	}

	private static async Task<ToolResult> DescribePlaybook(JsonElement args, string playbookDir, CancellationToken ct)
	{
		if (!args.TryGetProperty("id", out var idEl))
		{
			return ToolResult.Fail("플레이북 id가 필요합니다.");
		}
		int parsed;
		int id = ((idEl.ValueKind == JsonValueKind.Number) ? idEl.GetInt32() : (int.TryParse(idEl.GetString(), out parsed) ? parsed : (-1)));
		PlaybookData playbook = await FindPlaybookById(playbookDir, id, ct);
		if (playbook == null)
		{
			return ToolResult.Fail($"ID {id}의 플레이북을 찾을 수 없습니다.");
		}
		StringBuilder sb = new StringBuilder();
		StringBuilder stringBuilder = sb;
		StringBuilder stringBuilder2 = stringBuilder;
		StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(13, 2, stringBuilder);
		handler.AppendLiteral("플레이북: ");
		handler.AppendFormatted(playbook.Name);
		handler.AppendLiteral(" (ID: ");
		handler.AppendFormatted(playbook.Id);
		handler.AppendLiteral(")");
		stringBuilder2.AppendLine(ref handler);
		stringBuilder = sb;
		StringBuilder stringBuilder3 = stringBuilder;
		handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder);
		handler.AppendLiteral("설명: ");
		handler.AppendFormatted(playbook.Description);
		stringBuilder3.AppendLine(ref handler);
		stringBuilder = sb;
		StringBuilder stringBuilder4 = stringBuilder;
		handler = new StringBuilder.AppendInterpolatedStringHandler(5, 1, stringBuilder);
		handler.AppendLiteral("생성일: ");
		handler.AppendFormatted(playbook.CreatedAt);
		stringBuilder4.AppendLine(ref handler);
		sb.AppendLine();
		sb.AppendLine("단계:");
		for (int i = 0; i < playbook.Steps.Count; i++)
		{
			stringBuilder = sb;
			StringBuilder stringBuilder5 = stringBuilder;
			handler = new StringBuilder.AppendInterpolatedStringHandler(4, 2, stringBuilder);
			handler.AppendLiteral("  ");
			handler.AppendFormatted(i + 1);
			handler.AppendLiteral(". ");
			handler.AppendFormatted(playbook.Steps[i]);
			stringBuilder5.AppendLine(ref handler);
		}
		if (playbook.ToolsUsed.Count > 0)
		{
			sb.AppendLine();
			stringBuilder = sb;
			StringBuilder stringBuilder6 = stringBuilder;
			handler = new StringBuilder.AppendInterpolatedStringHandler(7, 1, stringBuilder);
			handler.AppendLiteral("사용 도구: ");
			handler.AppendFormatted(string.Join(", ", playbook.ToolsUsed));
			stringBuilder6.AppendLine(ref handler);
		}
		return ToolResult.Ok(sb.ToString());
	}

	private static ToolResult DeletePlaybook(JsonElement args, string playbookDir)
	{
		if (!args.TryGetProperty("id", out var value))
		{
			return ToolResult.Fail("삭제할 플레이북 id가 필요합니다.");
		}
		int result;
		int num = ((value.ValueKind == JsonValueKind.Number) ? value.GetInt32() : (int.TryParse(value.GetString(), out result) ? result : (-1)));
		if (!Directory.Exists(playbookDir))
		{
			return ToolResult.Fail("저장된 플레이북이 없습니다.");
		}
		string[] files = Directory.GetFiles(playbookDir, $"{num}_*.json");
		if (files.Length == 0)
		{
			string[] files2 = Directory.GetFiles(playbookDir, "*.json");
			foreach (string path in files2)
			{
				try
				{
					string json = File.ReadAllText(path);
					PlaybookData playbookData = JsonSerializer.Deserialize<PlaybookData>(json);
					if (playbookData != null && playbookData.Id == num)
					{
						string name = playbookData.Name;
						File.Delete(path);
						return ToolResult.Ok($"플레이북 삭제됨: [{num}] {name}");
					}
				}
				catch
				{
				}
			}
			return ToolResult.Fail($"ID {num}의 플레이북을 찾을 수 없습니다.");
		}
		try
		{
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(files[0]);
			File.Delete(files[0]);
			return ToolResult.Ok("플레이북 삭제됨: " + fileNameWithoutExtension);
		}
		catch (Exception ex)
		{
			return ToolResult.Fail("플레이북 삭제 오류: " + ex.Message);
		}
	}

	private static int GetNextId(string playbookDir)
	{
		if (!Directory.Exists(playbookDir))
		{
			return 1;
		}
		int num = 0;
		string[] files = Directory.GetFiles(playbookDir, "*.json");
		foreach (string path in files)
		{
			try
			{
				string json = File.ReadAllText(path);
				PlaybookData playbookData = JsonSerializer.Deserialize<PlaybookData>(json);
				if (playbookData != null && playbookData.Id > num)
				{
					num = playbookData.Id;
				}
			}
			catch
			{
			}
		}
		return num + 1;
	}

	private static async Task<PlaybookData?> FindPlaybookById(string playbookDir, int id, CancellationToken ct)
	{
		if (!Directory.Exists(playbookDir))
		{
			return null;
		}
		string[] files = Directory.GetFiles(playbookDir, "*.json");
		foreach (string file in files)
		{
			try
			{
				PlaybookData pb = JsonSerializer.Deserialize<PlaybookData>(await File.ReadAllTextAsync(file, ct));
				if (pb != null && pb.Id == id)
				{
					return pb;
				}
			}
			catch
			{
			}
		}
		return null;
	}
}
