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

namespace AxCopilot.Services.Agent;

/// <summary>
/// 서브에이전트 생성 도구.
/// 메인 에이전트가 여러 독립 작업을 병렬로 실행할 수 있습니다.
/// 서브에이전트는 읽기 전용으로 실행되며, 파일 수정은 메인 에이전트가 수행합니다.
///
/// spawn_agent: 서브에이전트 생성 (비동기)
/// wait_agents: 모든 서브에이전트 결과 대기
/// </summary>
public class SubAgentTool : IAgentTool
{
    public string Name => "spawn_agent";

    public string Description =>
        "독립적인 서브에이전트를 생성하여 작업을 병렬로 실행합니다.\n" +
        "서브에이전트는 읽기 전용(파일 읽기, 검색, 분석)으로 실행됩니다.\n" +
        "여러 서브에이전트를 생성한 후 wait_agents로 결과를 수집하세요.\n" +
        "예: 큰 코드베이스에서 여러 파일을 동시에 분석할 때 유용합니다.";

    public ToolParameterSchema Parameters => new()
    {
        Properties = new()
        {
            ["task"] = new ToolProperty
            {
                Type = "string",
                Description = "서브에이전트가 수행할 작업 설명"
            },
            ["id"] = new ToolProperty
            {
                Type = "string",
                Description = "서브에이전트 식별자 (결과 수집 시 사용)"
            },
        },
        Required = new() { "task", "id" }
    };

    // 활성 서브에이전트 태스크 저장소
    private static readonly Dictionary<string, SubAgentTask> _activeTasks = new();
    private static readonly object _lock = new();

    public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default)
    {
        var task = args.TryGetProperty("task", out var t) ? t.GetString() ?? "" : "";
        var id = args.TryGetProperty("id", out var i) ? i.GetString() ?? "" : "";

        if (string.IsNullOrEmpty(task) || string.IsNullOrEmpty(id))
            return ToolResult.Fail("task와 id가 필요합니다.");

        // 오래된 완료 태스크 자동 정리
        CleanupStale();

        // 최대 동시 실행 수 제한
        var maxAgents = context.Llm?.MaxSubAgents ?? 3;
        lock (_lock)
        {
            var running = _activeTasks.Values.Count(t => t.CompletedAt == null);
            if (running >= maxAgents)
                return ToolResult.Fail($"서브에이전트 최대 동시 실행 수({maxAgents})에 도달했습니다. wait_agents로 완료된 결과를 수집한 후 다시 시도하세요.");
        }

        // 서브에이전트 컨텍스트: 읽기 전용
        var subContext = new AgentContext
        {
            WorkFolder = context.WorkFolder,
            Permission = "Deny", // 파일 수정 불가
            BlockedPaths = context.BlockedPaths,
            BlockedExtensions = context.BlockedExtensions,
            ActiveTab = context.ActiveTab,
        };

        // 비동기 실행
        var subTask = new SubAgentTask
        {
            Id = id,
            Task = task,
            StartedAt = DateTime.Now,
        };

        // 서브에이전트는 도구 직접 실행 (간단한 분석 작업)
        subTask.RunTask = System.Threading.Tasks.Task.Run(async () =>
        {
            try
            {
                var sb = new StringBuilder();
                sb.AppendLine($"[서브에이전트 {id}] 작업: {task}");

                // 기본 분석: 작업 폴더 스캔 결과 반환
                var folderMap = new FolderMapTool();
                var mapResult = await folderMap.ExecuteAsync(
                    JsonDocument.Parse($"{{\"path\":\"{context.WorkFolder.Replace("\\", "\\\\")}\"}}").RootElement,
                    subContext, ct);

                sb.AppendLine($"프로젝트 구조:\n{mapResult.Output}");
                subTask.Result = sb.ToString();
                subTask.Success = true;
            }
            catch (Exception ex)
            {
                subTask.Result = $"오류: {ex.Message}";
                subTask.Success = false;
            }
            subTask.CompletedAt = DateTime.Now;
        }, ct);

        lock (_lock)
        {
            _activeTasks[id] = subTask;
        }

        return ToolResult.Ok($"서브에이전트 '{id}' 시작됨. 작업: {task}\nwait_agents로 결과를 수집하세요.");
    }

    /// <summary>활성 서브에이전트 목록을 반환합니다.</summary>
    public static IReadOnlyDictionary<string, SubAgentTask> ActiveTasks
    {
        get { lock (_lock) return new Dictionary<string, SubAgentTask>(_activeTasks); }
    }

    /// <summary>모든 서브에이전트 결과를 수집합니다.</summary>
    public static async Task<string> WaitAllAsync(CancellationToken ct = default)
    {
        List<SubAgentTask> tasks;
        lock (_lock)
        {
            tasks = _activeTasks.Values.ToList();
        }

        if (tasks.Count == 0)
            return "활성 서브에이전트가 없습니다.";

        // 모든 태스크 대기
        await System.Threading.Tasks.Task.WhenAll(tasks.Where(t => t.RunTask != null).Select(t => t.RunTask!));

        var sb = new StringBuilder();
        sb.AppendLine($"총 {tasks.Count}개 서브에이전트 결과:");
        foreach (var task in tasks)
        {
            var status = task.Success ? "✓" : "✗";
            var duration = task.CompletedAt.HasValue ? $"{(task.CompletedAt.Value - task.StartedAt).TotalSeconds:F1}초" : "진행 중";
            sb.AppendLine($"\n--- [{status}] {task.Id} ({duration}) ---");
            sb.AppendLine(task.Result ?? "(결과 없음)");
        }

        // 정리
        lock (_lock) _activeTasks.Clear();

        return sb.ToString();
    }

    /// <summary>10분 이상 경과한 완료된 서브에이전트를 자동 정리합니다.</summary>
    public static void CleanupStale()
    {
        lock (_lock)
        {
            var stale = _activeTasks
                .Where(kv => kv.Value.CompletedAt.HasValue &&
                             (DateTime.Now - kv.Value.CompletedAt.Value).TotalMinutes > 10)
                .Select(kv => kv.Key)
                .ToList();
            foreach (var key in stale)
                _activeTasks.Remove(key);
        }
    }
}

/// <summary>서브에이전트 결과 대기 도구.</summary>
public class WaitAgentsTool : IAgentTool
{
    public string Name => "wait_agents";
    public string Description => "실행 중인 모든 서브에이전트의 결과를 수집합니다. spawn_agent로 시작한 서브에이전트가 모두 완료될 때까지 대기합니다.";

    public ToolParameterSchema Parameters => new()
    {
        Properties = new(),
        Required = new()
    };

    public async Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct = default)
    {
        var result = await SubAgentTool.WaitAllAsync(ct);
        return ToolResult.Ok(result);
    }
}

/// <summary>서브에이전트 태스크 상태.</summary>
public class SubAgentTask
{
    public string Id { get; init; } = "";
    public string Task { get; init; } = "";
    public DateTime StartedAt { get; init; }
    public DateTime? CompletedAt { get; set; }
    public bool Success { get; set; }
    public string? Result { get; set; }
    public System.Threading.Tasks.Task? RunTask { get; set; }
}
