using AgentSmith.Application.Services.Health;
using AgentSmith.Application.Services;
using AgentSmith.Contracts.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace AgentSmith.Server.Services.Webhooks;

/// <summary>
/// Processes validated webhook requests: detects platform, verifies signature, dispatches
/// to handlers, and routes results. p0140b: ticket-event handlers now perform their own
/// spawn (via SpawnPipelineRunsUseCase) and return HandledNoRoute — the old structured-
/// ticket routing branch was deleted. Remaining post-dispatch paths: DialogueAnswer (PR
/// /approve|/reject) routes via WebhookDialogueRouter; TriggerInput legacy path runs the
/// free-form ExecutePipelineUseCase.
/// </summary>
internal sealed class WebhookRequestProcessor(
    IServiceProvider services,
    string configPath,
    ILogger logger)
{
    public async Task<(int StatusCode, string Body)> ProcessAsync(
        string path, string body, IDictionary<string, string> headers)
    {
        var (platform, eventType) = WebhookPlatformDetector.Detect(path, body, headers);
        if (platform is null)
            return (200, "Unknown platform");

        var verifier = new WebhookSignatureVerifier(services, logger);
        if (!verifier.Validate(platform, body, headers))
        {
            logger.LogWarning("Signature validation failed for {Platform}", platform);
            return (401, "Signature validation failed");
        }

        var handlers = services.GetServices<IWebhookHandler>();
        var result = await DispatchAsync(handlers, platform, eventType!, body, headers);

        if (!result.Handled)
            return (200, "Event ignored");

        if (result.DialogueAnswer is not null)
        {
            if (!IsRedisAvailable()) return (503, "redis_unavailable");
            var router = new WebhookDialogueRouter(services, logger);
            _ = router.RouteAsync(result.DialogueAnswer);
            return (202, "Accepted: dialogue answer");
        }

        if (result.TriggerInput is not null)
        {
            _ = ExecuteLegacyAsync(result.TriggerInput, result.Pipeline, result.InitialContext);
            return (202, $"Accepted: {result.TriggerInput}");
        }

        logger.LogInformation("Webhook: handler completed spawn for {Platform}/{Event}", platform, eventType);
        return (202, "Accepted");
    }

    private bool IsRedisAvailable()
    {
        var redisHealth = services.GetServices<ISubsystemHealth>()
            .FirstOrDefault(h => h.Name == "redis");
        return redisHealth?.State == SubsystemState.Up;
    }

    private static async Task<WebhookResult> DispatchAsync(
        IEnumerable<IWebhookHandler> handlers, string platform, string eventType,
        string body, IDictionary<string, string> headers)
    {
        foreach (var handler in handlers)
        {
            if (!handler.CanHandle(platform, eventType)) continue;
            var result = await handler.HandleAsync(body, headers);
            if (result.Handled) return result;
        }
        return WebhookResult.NotHandled();
    }

    private async Task ExecuteLegacyAsync(
        string input, string? pipelineOverride, Dictionary<string, object>? initialContext = null)
    {
        try
        {
            var useCase = services.GetRequiredService<ExecutePipelineUseCase>();
            var result = await useCase.ExecuteAsync(
                input, configPath, headless: true, pipelineOverride, CancellationToken.None, initialContext);
            logger.LogInformation(result.IsSuccess
                ? "Run completed: {Message}" : "Run failed: {Message}", result.Message);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Run failed for: {Input}", input);
        }
    }
}
