using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Options;

namespace GerbilManagerWebAPI.SaleAd
{
    /// <summary>
    /// FEAT-12a: provider-agnostic AI client for sale-ad generation.
    ///
    /// Speaks the OpenAI-compatible chat-completions wire shape — deliberately
    /// WITHOUT any vendor SDK: a plain JSON POST to {AI:BaseUrl}/chat/completions
    /// with a Bearer key covers Google Gemini (compat endpoint), Groq, Mistral,
    /// local Ollama and any future provider. The wire shape IS the abstraction.
    /// </summary>
    public sealed class SaleAdService(HttpClient http, IOptions<AiOptions> options)
    {
        private static readonly JsonSerializerOptions JsonOptions = new()
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        };

        public async Task<SaleAdResult> GenerateAsync(SaleAdRequest request, CancellationToken ct = default)
        {
            var ai = options.Value;
            if (!ai.IsConfigured)
            {
                return new SaleAdResult(SaleAdStatus.NotConfigured, null,
                    "KI-Anbieter ist nicht konfiguriert (AI__BaseUrl / AI__ApiKey / AI__Model).");
            }

            var payload = new ChatRequest(
                Model: ai.Model!,
                Messages:
                [
                    new ChatMessage("system", SaleAdPromptBuilder.BuildSystemPrompt()),
                    new ChatMessage("user", SaleAdPromptBuilder.BuildUserPrompt(request)),
                ],
                Temperature: 0.7);

            using var httpRequest = new HttpRequestMessage(HttpMethod.Post, BuildCompletionsUri(ai.BaseUrl!))
            {
                Content = new StringContent(JsonSerializer.Serialize(payload, JsonOptions),
                    Encoding.UTF8, "application/json"),
            };
            httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", ai.ApiKey);

            try
            {
                using var response = await http.SendAsync(httpRequest, ct);
                var body = await response.Content.ReadAsStringAsync(ct);
                if (!response.IsSuccessStatusCode)
                {
                    return new SaleAdResult(SaleAdStatus.UpstreamError, null,
                        $"KI-Anbieter antwortete mit HTTP {(int)response.StatusCode}.");
                }

                var completion = JsonSerializer.Deserialize<ChatResponse>(body, JsonOptions);
                var text = completion?.Choices?.FirstOrDefault()?.Message?.Content?.Trim();
                return string.IsNullOrWhiteSpace(text)
                    ? new SaleAdResult(SaleAdStatus.UpstreamError, null,
                        "KI-Antwort enthielt keinen Text.")
                    : new SaleAdResult(SaleAdStatus.Ok, text);
            }
            catch (Exception ex) when (ex is HttpRequestException or TaskCanceledException or JsonException)
            {
                return new SaleAdResult(SaleAdStatus.UpstreamError, null,
                    $"KI-Anbieter nicht erreichbar: {ex.Message}");
            }
        }

        /// <summary>{BaseUrl}/chat/completions — tolerant of a trailing slash on BaseUrl.</summary>
        internal static Uri BuildCompletionsUri(string baseUrl) =>
            new($"{baseUrl.TrimEnd('/')}/chat/completions");

        // ── OpenAI-compatible wire records (request + the slice of the response we read) ──
        internal sealed record ChatRequest(string Model, List<ChatMessage> Messages, double? Temperature);

        internal sealed record ChatMessage(string Role, string Content);

        internal sealed record ChatResponse(List<ChatChoice>? Choices);

        internal sealed record ChatChoice(ChatMessage? Message);
    }
}
