using System.Text.Json;

namespace AxCopilot.Services.Agent.Sdk;

/// <summary>
/// Phase 31-D: SDK 훅 콜백 핸들러.
/// 에이전트 훅 이벤트를 SDK 호스트에 JSON으로 전달하고,
/// 호스트의 응답을 훅 결과로 반환합니다.
///
/// CC의 SdkHookCallbackHandler와 동등:
///   - PreToolUse → Host에 CanUseTool 질의 → Allow/Deny 응답
///   - 커스텀 훅 이벤트 → Host 알림
/// </summary>
public class SdkHookCallbackHandler
{
    private readonly Func<SdkMessage, Task> _sendMessage;
    private readonly HashSet<string> _registeredEvents;

    // 대기 중인 권한 요청 (requestId → TaskCompletionSource)
    private readonly Dictionary<string, TaskCompletionSource<bool>> _pendingPermissions = new();

    public SdkHookCallbackHandler(
        Func<SdkMessage, Task> sendMessage,
        IEnumerable<string>? registeredEvents = null)
    {
        _sendMessage = sendMessage;
        _registeredEvents = registeredEvents != null
            ? new HashSet<string>(registeredEvents, StringComparer.OrdinalIgnoreCase)
            : new HashSet<string>(StringComparer.OrdinalIgnoreCase);
    }

    /// <summary>이벤트가 SDK 콜백으로 등록되었는지 확인합니다.</summary>
    public bool IsRegistered(string eventName)
        => _registeredEvents.Contains(eventName) || _registeredEvents.Contains("*");

    /// <summary>
    /// 도구 사용 허가를 SDK 호스트에 요청합니다.
    /// 타임아웃(30초) 내 응답이 없으면 Deny 반환.
    /// </summary>
    public async Task<bool> RequestToolPermissionAsync(
        string toolName, string? filePath, object? input,
        CancellationToken ct = default)
    {
        var requestId = Guid.NewGuid().ToString("N")[..8];
        var tcs = new TaskCompletionSource<bool>();
        ct.Register(() => tcs.TrySetResult(false));

        lock (_pendingPermissions)
            _pendingPermissions[requestId] = tcs;

        try
        {
            await _sendMessage(new SdkMessage
            {
                Type = SdkMessageType.CanUseTool,
                RequestId = requestId,
                Data = new SdkCanUseToolData
                {
                    ToolName = toolName,
                    FilePath = filePath,
                    Input = input,
                },
            });

            // 30초 타임아웃
            using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
            using var linked = CancellationTokenSource.CreateLinkedTokenSource(ct, timeoutCts.Token);
            linked.Token.Register(() => tcs.TrySetResult(false));

            return await tcs.Task;
        }
        finally
        {
            lock (_pendingPermissions)
                _pendingPermissions.Remove(requestId);
        }
    }

    /// <summary>호스트로부터 권한 응답을 수신합니다.</summary>
    public void HandlePermissionResponse(string requestId, bool allowed)
    {
        TaskCompletionSource<bool>? tcs;
        lock (_pendingPermissions)
        {
            if (!_pendingPermissions.TryGetValue(requestId, out tcs)) return;
        }
        tcs.TrySetResult(allowed);
    }

    /// <summary>훅 이벤트를 SDK 호스트에 알립니다 (비동기, 응답 불필요).</summary>
    public async Task NotifyHookEventAsync(string eventKind, string? toolName, string? summary)
    {
        if (!IsRegistered(eventKind)) return;

        await _sendMessage(new SdkMessage
        {
            Type = SdkMessageType.HookEvent,
            Data = new
            {
                eventKind,
                toolName,
                summary,
            },
        });
    }
}
