using System.IO;
using System.Text;
using System.Text.Json;

namespace AxCopilot.Services.Agent;

/// <summary>파일/폴더 메타 정보(크기, 수정일, 줄 수 등) 조회 도구.</summary>
public class FileInfoTool : IAgentTool
{
    public string Name => "file_info";
    public string Description =>
        "Get file or directory metadata without reading contents. " +
        "Returns: size, created/modified dates, line count (files), item count (directories), encoding hint.";

    public ToolParameterSchema Parameters => new()
    {
        Properties = new()
        {
            ["path"] = new()
            {
                Type = "string",
                Description = "File or directory path",
            },
        },
        Required = ["path"],
    };

    public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default)
    {
        var rawPath = args.GetProperty("path").GetString() ?? "";
        var path = Path.IsPathRooted(rawPath) ? rawPath : Path.Combine(context.WorkFolder, rawPath);

        if (!context.IsPathAllowed(path))
            return Task.FromResult(ToolResult.Fail($"경로 접근 차단: {path}"));

        try
        {
            if (File.Exists(path))
            {
                var fi = new FileInfo(path);
                var sb = new StringBuilder();
                sb.AppendLine($"Type: File");
                sb.AppendLine($"Path: {fi.FullName}");
                sb.AppendLine($"Size: {FormatSize(fi.Length)} ({fi.Length:N0} bytes)");
                sb.AppendLine($"Extension: {fi.Extension}");
                sb.AppendLine($"Created: {fi.CreationTime:yyyy-MM-dd HH:mm:ss}");
                sb.AppendLine($"Modified: {fi.LastWriteTime:yyyy-MM-dd HH:mm:ss}");
                sb.AppendLine($"ReadOnly: {fi.IsReadOnly}");

                // 텍스트 파일이면 줄 수 카운트 (최대 100만 줄까지)
                var textExts = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
                    { ".cs", ".py", ".js", ".ts", ".java", ".cpp", ".c", ".h", ".xml", ".json",
                      ".yaml", ".yml", ".md", ".txt", ".csv", ".html", ".htm", ".css", ".sql",
                      ".sh", ".bat", ".ps1", ".config", ".ini", ".log", ".xaml" };
                if (textExts.Contains(fi.Extension) && fi.Length < 50 * 1024 * 1024)
                {
                    var lineCount = File.ReadLines(path).Take(1_000_000).Count();
                    sb.AppendLine($"Lines: {lineCount:N0}{(lineCount >= 1_000_000 ? "+" : "")}");
                }

                return Task.FromResult(ToolResult.Ok(sb.ToString()));
            }

            if (Directory.Exists(path))
            {
                var di = new DirectoryInfo(path);
                var files = di.GetFiles("*", SearchOption.TopDirectoryOnly);
                var dirs = di.GetDirectories();
                var totalSize = files.Sum(f => f.Length);

                var sb = new StringBuilder();
                sb.AppendLine($"Type: Directory");
                sb.AppendLine($"Path: {di.FullName}");
                sb.AppendLine($"Files: {files.Length}");
                sb.AppendLine($"Subdirectories: {dirs.Length}");
                sb.AppendLine($"Total Size (top-level files): {FormatSize(totalSize)}");
                sb.AppendLine($"Created: {di.CreationTime:yyyy-MM-dd HH:mm:ss}");
                sb.AppendLine($"Modified: {di.LastWriteTime:yyyy-MM-dd HH:mm:ss}");

                return Task.FromResult(ToolResult.Ok(sb.ToString()));
            }

            return Task.FromResult(ToolResult.Fail($"경로를 찾을 수 없습니다: {path}"));
        }
        catch (Exception ex)
        {
            return Task.FromResult(ToolResult.Fail($"정보 조회 오류: {ex.Message}"));
        }
    }

    private static string FormatSize(long bytes) => bytes switch
    {
        < 1024 => $"{bytes}B",
        < 1024 * 1024 => $"{bytes / 1024.0:F1}KB",
        < 1024L * 1024 * 1024 => $"{bytes / (1024.0 * 1024):F1}MB",
        _ => $"{bytes / (1024.0 * 1024 * 1024):F2}GB",
    };
}
