using System.Text;
using System.Text.Json;
using LiquidCode.Tester.Common.Models;

namespace LiquidCode.Tester.Worker.Services;

public class CallbackService : ICallbackService
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly ILogger<CallbackService> _logger;

    public CallbackService(IHttpClientFactory httpClientFactory, ILogger<CallbackService> logger)
    {
        _httpClientFactory = httpClientFactory;
        _logger = logger;
    }

    public async Task SendStatusAsync(string callbackUrl, TesterResponseModel response)
    {
        // Check if callback should be logged instead of sent via HTTP
        if (IsLogCallback(callbackUrl))
        {
            LogCallback(response);
            return;
        }

        _logger.LogInformation("Sending status update to {CallbackUrl} for submit {SubmitId}", callbackUrl, response.SubmitId);

        try
        {
            var httpClient = _httpClientFactory.CreateClient();
            var json = JsonSerializer.Serialize(response);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            var httpResponse = await httpClient.PostAsync(callbackUrl, content);

            if (!httpResponse.IsSuccessStatusCode)
            {
                var responseBody = await httpResponse.Content.ReadAsStringAsync();
                _logger.LogWarning("Callback returned non-success status {StatusCode} with body: {Body}",
                    (int)httpResponse.StatusCode, Truncate(responseBody, 2048));
            }

            httpResponse.EnsureSuccessStatusCode();

            _logger.LogInformation("Status update sent successfully");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send status update to {CallbackUrl}", callbackUrl);
            // Don't throw - callback failures shouldn't stop testing
        }
    }

    private static string Truncate(string value, int maxLength)
    {
        if (string.IsNullOrEmpty(value) || value.Length <= maxLength)
        {
            return value;
        }

        return value.Substring(0, maxLength) + "…";
    }

    private bool IsLogCallback(string callbackUrl)
    {
        if (string.IsNullOrWhiteSpace(callbackUrl))
        {
            return false;
        }

        var normalized = callbackUrl.Trim().ToLowerInvariant();
        return normalized == "log" ||
               normalized == "console" ||
               normalized.StartsWith("log://");
    }

    private void LogCallback(TesterResponseModel response)
    {
        var options = new JsonSerializerOptions
        {
            WriteIndented = true,
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };

        var json = JsonSerializer.Serialize(response, options);

        _logger.LogInformation(
            "\n" +
            "╔═══════════════════════════════════════════════════════════════╗\n" +
            "║                    CALLBACK RESULT                            ║\n" +
            "╠═══════════════════════════════════════════════════════════════╣\n" +
            "{Json}\n" +
            "╚═══════════════════════════════════════════════════════════════╝",
            json);
    }
}
