using System.Text.Json;

namespace AxCopilot.Services.Agent;

/// <summary>
/// Phase 18-A: 전문 서브에이전트에 작업 위임 도구.
/// IAgentTool 구현. ToolRegistry.CreateDefault()에 등록 필요.
/// </summary>
public class DelegateAgentTool : IAgentTool, IConditionalTool
{
    /// <summary>AI 비활성화 시 서브에이전트 위임 불가.</summary>
    public bool IsEnabled(ToolEnvironmentContext env) => env.AiEnabled;

    public string Name => "delegate";
    public string Description =>
        "전문 에이전트에 작업을 위임합니다. " +
        "researcher(조사/검색), code-reviewer(코드리뷰), implementer(구현), " +
        "security-auditor(보안감사), doc-writer(문서작성) 중 선택.";

    public ToolParameterSchema Parameters => new()
    {
        Properties = new Dictionary<string, ToolProperty>
        {
            ["agent_type"] = new()
            {
                Type = "string",
                Description = "위임할 에이전트 유형",
                Enum = new List<string>
                {
                    "researcher", "code-reviewer", "implementer",
                    "security-auditor", "doc-writer"
                }
            },
            ["task"] = new()
            {
                Type = "string",
                Description = "에이전트에게 전달할 작업 설명"
            },
            ["context"] = new()
            {
                Type = "string",
                Description = "에이전트에게 전달할 추가 컨텍스트 (파일 내용, 배경 정보 등)"
            },
            ["isolation"] = new()
            {
                Type = "string",
                Description = "격리 수준: none(기본) | worktree(git worktree 격리)",
                Enum = new List<string> { "none", "worktree" }
            }
        },
        Required = new List<string> { "agent_type", "task" }
    };

    private readonly BackgroundAgentService _bgService;
    private readonly IAgentMemoryRepository _memoryRepo;
    private readonly WorktreeManager? _worktreeManager;

    // 서브에이전트 실행 함수 (AgentLoopService에서 주입)
    private Func<string, string, string, CancellationToken, Task<string>>? _subAgentRunner;

    public DelegateAgentTool(
        BackgroundAgentService bgService,
        IAgentMemoryRepository memoryRepo,
        WorktreeManager? worktreeManager = null)
    {
        _bgService = bgService;
        _memoryRepo = memoryRepo;
        _worktreeManager = worktreeManager;
    }

    /// <summary>서브에이전트 실행 함수를 주입합니다 (AgentLoopService에서 호출).</summary>
    public void SetSubAgentRunner(Func<string, string, string, CancellationToken, Task<string>> runner)
        => _subAgentRunner = runner;

    public async Task<ToolResult> ExecuteAsync(
        JsonElement args,
        AgentContext context,
        CancellationToken ct = default)
    {
        var agentType = args.TryGetProperty("agent_type", out var at) ? at.GetString() ?? "researcher" : "researcher";
        var task = args.TryGetProperty("task", out var t) ? t.GetString() ?? "" : "";
        var ctx = args.TryGetProperty("context", out var c) ? c.GetString() ?? "" : "";
        var isolation = args.TryGetProperty("isolation", out var iso) ? iso.GetString() ?? "none" : "none";

        if (string.IsNullOrWhiteSpace(task))
            return ToolResult.Fail("작업 설명(task)이 필요합니다.");

        if (_subAgentRunner == null)
            return ToolResult.Fail("서브에이전트 실행기가 설정되지 않았습니다.");

        // worktree 격리
        Worktree? worktree = null;
        if (isolation == "worktree" && _worktreeManager != null && !string.IsNullOrEmpty(context.WorkFolder))
        {
            var branchName = $"ax-{agentType}-{DateTime.UtcNow:yyMMddHHmm}";
            worktree = await _worktreeManager.CreateAsync(context.WorkFolder, branchName, ct);
        }

        var workDir = worktree?.Path ?? context.WorkFolder;

        // 에이전트 타입별 메모리 로드 + 컨텍스트 보강
        var memory = await _memoryRepo.LoadMemoryAsync(agentType);
        var fullContext = string.IsNullOrEmpty(memory)
            ? ctx
            : ctx + $"\n\n## 이전 학습:\n{memory}";

        // 서브에이전트 실행 (동기 대기)
        try
        {
            var result = await _subAgentRunner(agentType, task, fullContext, ct);

            // 결과 크기 제한
            if (result.Length > 100_000)
                result = result[..100_000] + "\n\n[결과가 100,000자를 초과하여 잘림]";

            // worktree 정리 (완료 후)
            if (worktree != null)
                await _worktreeManager!.DisposeWorktreeAsync(worktree, keepBranch: false, ct);

            return ToolResult.Ok($"[{agentType}] 완료:\n\n{result}");
        }
        catch (Exception ex)
        {
            if (worktree != null)
                try { await _worktreeManager!.DisposeWorktreeAsync(worktree, ct: CancellationToken.None); }
                catch (Exception) { }

            return ToolResult.Fail($"[{agentType}] 실행 실패: {ex.Message}");
        }
    }
}
