using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace AxCopilot.Services.Agent;

public class DateTimeTool : IAgentTool
{
	public string Name => "datetime_tool";

	public string Description => "Date/time utility tool. Actions: 'now' — get current date/time in various formats; 'parse' — parse a date string into standard format; 'diff' — calculate difference between two dates; 'add' — add/subtract days/hours/minutes to a date; 'epoch' — convert between Unix epoch and datetime; 'format' — format a date into specified pattern.";

	public ToolParameterSchema Parameters
	{
		get
		{
			ToolParameterSchema toolParameterSchema = new ToolParameterSchema();
			Dictionary<string, ToolProperty> dictionary = new Dictionary<string, ToolProperty>();
			ToolProperty obj = new ToolProperty
			{
				Type = "string",
				Description = "Action to perform"
			};
			int num = 6;
			List<string> list = new List<string>(num);
			CollectionsMarshal.SetCount(list, num);
			Span<string> span = CollectionsMarshal.AsSpan(list);
			span[0] = "now";
			span[1] = "parse";
			span[2] = "diff";
			span[3] = "add";
			span[4] = "epoch";
			span[5] = "format";
			obj.Enum = list;
			dictionary["action"] = obj;
			dictionary["date"] = new ToolProperty
			{
				Type = "string",
				Description = "Date string (for parse/diff/add/format/epoch). For epoch: Unix timestamp in seconds."
			};
			dictionary["date2"] = new ToolProperty
			{
				Type = "string",
				Description = "Second date string (for diff action)"
			};
			dictionary["amount"] = new ToolProperty
			{
				Type = "string",
				Description = "Amount to add (for add action). E.g. '7' for 7 days"
			};
			ToolProperty obj2 = new ToolProperty
			{
				Type = "string",
				Description = "Unit for add action"
			};
			num = 6;
			List<string> list2 = new List<string>(num);
			CollectionsMarshal.SetCount(list2, num);
			Span<string> span2 = CollectionsMarshal.AsSpan(list2);
			span2[0] = "days";
			span2[1] = "hours";
			span2[2] = "minutes";
			span2[3] = "seconds";
			span2[4] = "months";
			span2[5] = "years";
			obj2.Enum = list2;
			dictionary["unit"] = obj2;
			dictionary["pattern"] = new ToolProperty
			{
				Type = "string",
				Description = "Format pattern (for format action). E.g. 'yyyy-MM-dd HH:mm:ss', 'ddd MMM d yyyy'"
			};
			toolParameterSchema.Properties = dictionary;
			num = 1;
			List<string> list3 = new List<string>(num);
			CollectionsMarshal.SetCount(list3, num);
			CollectionsMarshal.AsSpan(list3)[0] = "action";
			toolParameterSchema.Required = list3;
			return toolParameterSchema;
		}
	}

	public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default(CancellationToken))
	{
		string text = args.GetProperty("action").GetString() ?? "";
		try
		{
			if (1 == 0)
			{
			}
			ToolResult result = text switch
			{
				"now" => Now(), 
				"parse" => Parse(args), 
				"diff" => Diff(args), 
				"add" => Add(args), 
				"epoch" => Epoch(args), 
				"format" => FormatDate(args), 
				_ => ToolResult.Fail("Unknown action: " + text), 
			};
			if (1 == 0)
			{
			}
			return Task.FromResult(result);
		}
		catch (Exception ex)
		{
			return Task.FromResult(ToolResult.Fail("DateTime 오류: " + ex.Message));
		}
	}

	private static ToolResult Now()
	{
		DateTime now = DateTime.Now;
		DateTime utcNow = DateTime.UtcNow;
		long value = new DateTimeOffset(utcNow).ToUnixTimeSeconds();
		return ToolResult.Ok($"Local:  {now:yyyy-MM-dd HH:mm:ss (ddd)} ({TimeZoneInfo.Local.DisplayName})\nUTC:    {utcNow:yyyy-MM-dd HH:mm:ss}\nISO:    {now:O}\nEpoch:  {value}\nWeek:   {CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(now, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday)}");
	}

	private static ToolResult Parse(JsonElement args)
	{
		JsonElement value;
		string text = (args.TryGetProperty("date", out value) ? (value.GetString() ?? "") : "");
		if (string.IsNullOrEmpty(text))
		{
			return ToolResult.Fail("'date' parameter is required");
		}
		if (!DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out var result) && !DateTime.TryParse(text, CultureInfo.CurrentCulture, DateTimeStyles.None, out result))
		{
			return ToolResult.Fail("Cannot parse date: '" + text + "'");
		}
		return ToolResult.Ok($"Parsed:  {result:yyyy-MM-dd HH:mm:ss}\nDay:     {result:dddd}\nISO:     {result:O}\nEpoch:   {new DateTimeOffset(result).ToUnixTimeSeconds()}");
	}

	private static ToolResult Diff(JsonElement args)
	{
		JsonElement value;
		string text = (args.TryGetProperty("date", out value) ? (value.GetString() ?? "") : "");
		JsonElement value2;
		string text2 = (args.TryGetProperty("date2", out value2) ? (value2.GetString() ?? "") : "");
		if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2))
		{
			return ToolResult.Fail("'date' and 'date2' parameters are required");
		}
		if (!DateTime.TryParse(text, out var result))
		{
			return ToolResult.Fail("Cannot parse date: '" + text + "'");
		}
		if (!DateTime.TryParse(text2, out var result2))
		{
			return ToolResult.Fail("Cannot parse date: '" + text2 + "'");
		}
		TimeSpan timeSpan = result2 - result;
		return ToolResult.Ok($"From: {result:yyyy-MM-dd HH:mm:ss}\nTo:   {result2:yyyy-MM-dd HH:mm:ss}\n\nDifference:\n  {Math.Abs(timeSpan.TotalDays):F1} days\n  {Math.Abs(timeSpan.TotalHours):F1} hours\n  {Math.Abs(timeSpan.TotalMinutes):F0} minutes\n  {Math.Abs(timeSpan.TotalSeconds):F0} seconds\n  ({((timeSpan.TotalDays >= 0.0) ? "forward" : "backward")})");
	}

	private static ToolResult Add(JsonElement args)
	{
		JsonElement value;
		string text = (args.TryGetProperty("date", out value) ? (value.GetString() ?? "") : "");
		JsonElement value2;
		string text2 = (args.TryGetProperty("amount", out value2) ? (value2.GetString() ?? "0") : "0");
		JsonElement value3;
		string text3 = (args.TryGetProperty("unit", out value3) ? (value3.GetString() ?? "days") : "days");
		if (string.IsNullOrEmpty(text))
		{
			return ToolResult.Fail("'date' parameter is required");
		}
		if (!DateTime.TryParse(text, out var result))
		{
			return ToolResult.Fail("Cannot parse date: '" + text + "'");
		}
		if (!double.TryParse(text2, out var result2))
		{
			return ToolResult.Fail("Invalid amount: '" + text2 + "'");
		}
		if (1 == 0)
		{
		}
		DateTime dateTime = text3 switch
		{
			"days" => result.AddDays(result2), 
			"hours" => result.AddHours(result2), 
			"minutes" => result.AddMinutes(result2), 
			"seconds" => result.AddSeconds(result2), 
			"months" => result.AddMonths((int)result2), 
			"years" => result.AddYears((int)result2), 
			_ => result.AddDays(result2), 
		};
		if (1 == 0)
		{
		}
		DateTime value4 = dateTime;
		return ToolResult.Ok($"Original: {result:yyyy-MM-dd HH:mm:ss}\nAdded:    {result2} {text3}\nResult:   {value4:yyyy-MM-dd HH:mm:ss} ({value4:dddd})");
	}

	private static ToolResult Epoch(JsonElement args)
	{
		JsonElement value;
		string text = (args.TryGetProperty("date", out value) ? (value.GetString() ?? "") : "");
		if (string.IsNullOrEmpty(text))
		{
			return ToolResult.Fail("'date' parameter is required");
		}
		if (long.TryParse(text, out var result))
		{
			DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(result);
			return ToolResult.Ok($"Epoch:  {result}\nUTC:    {dateTimeOffset.UtcDateTime:yyyy-MM-dd HH:mm:ss}\nLocal:  {dateTimeOffset.LocalDateTime:yyyy-MM-dd HH:mm:ss}");
		}
		if (DateTime.TryParse(text, out var result2))
		{
			long value2 = new DateTimeOffset(result2).ToUnixTimeSeconds();
			return ToolResult.Ok($"Date:   {result2:yyyy-MM-dd HH:mm:ss}\nEpoch:  {value2}");
		}
		return ToolResult.Fail("Cannot parse: '" + text + "'");
	}

	private static ToolResult FormatDate(JsonElement args)
	{
		JsonElement value;
		string text = (args.TryGetProperty("date", out value) ? (value.GetString() ?? "") : "");
		JsonElement value2;
		string text2 = (args.TryGetProperty("pattern", out value2) ? (value2.GetString() ?? "yyyy-MM-dd") : "yyyy-MM-dd");
		if (string.IsNullOrEmpty(text))
		{
			return ToolResult.Fail("'date' parameter is required");
		}
		if (!DateTime.TryParse(text, out var result))
		{
			return ToolResult.Fail("Cannot parse date: '" + text + "'");
		}
		return ToolResult.Ok(result.ToString(text2, CultureInfo.InvariantCulture));
	}
}
