using System.Diagnostics;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace Nalu.Web.Services.LlmRouter;

public class GroqProvider(HttpClient http, IConfiguration config, ILogger<GroqProvider> logger) : ILlmProvider
{
    public string Name => "groq";

    public async Task<LlmResponse> CompleteAsync(LlmRequest request, CancellationToken ct)
    {
        var model = config["Groq:Model"] ?? "llama-3.3-70b-versatile";
        var body = BuildBody(model, request);

        var sw = Stopwatch.StartNew();
        using var httpReq = new HttpRequestMessage(HttpMethod.Post, "chat/completions")
        {
            Content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json")
        };

        HttpResponseMessage resp;
        try
        {
            resp = await http.SendAsync(httpReq, ct);
        }
        catch (TaskCanceledException) when (!ct.IsCancellationRequested)
        {
            throw new TimeoutException("Groq request timed out");
        }

        if (resp.StatusCode == HttpStatusCode.TooManyRequests)
            throw new RateLimitException(Name);

        if ((int)resp.StatusCode >= 500)
        {
            logger.LogWarning("Groq server error {Status}", resp.StatusCode);
            throw new RateLimitException(Name); // treat as transient
        }

        if (!resp.IsSuccessStatusCode)
        {
            var err = await resp.Content.ReadAsStringAsync(ct);
            throw new InvalidOperationException($"Groq {resp.StatusCode}: {err}");
        }

        var content = await ExtractContent(resp, ct);
        return new LlmResponse { Content = content, Provider = Name, LatencyMs = (int)sw.ElapsedMilliseconds };
    }

    private static object BuildBody(string model, LlmRequest r) => new
    {
        model,
        messages = new[]
        {
            new { role = "system", content = r.SystemPrompt },
            new { role = "user",   content = r.UserMessage }
        },
        max_tokens = r.MaxTokens,
        temperature = r.Temperature,
        response_format = new { type = "json_object" }
    };

    private static async Task<string> ExtractContent(HttpResponseMessage resp, CancellationToken ct)
    {
        var json = await resp.Content.ReadAsStringAsync(ct);
        var doc = JsonNode.Parse(json);
        var content = doc?["choices"]?[0]?["message"]?["content"]?.GetValue<string>();
        return content ?? throw new InvalidOperationException("Empty content in Groq response");
    }
}
