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

namespace GerbilManagerWebAPI.Ai
{
    public enum AiCallStatus
    {
        Ok,
        /// <summary>AI section not (fully) configured -> callers map to 503 "AiKeyMissing".</summary>
        NotConfigured,
        /// <summary>Provider call failed -> callers map to 502 "AiUpstreamError".</summary>
        UpstreamError,
    }

    public sealed record AiCallResult(AiCallStatus Status, string? Text, string? Error = null);

    /// <summary>
    /// INBOX-2: provider-agnostic chat client, extracted from SaleAdService so the
    /// reply-draft (and future AI features) reuse the SAME wire implementation:
    /// plain JSON POST to {AI:BaseUrl}/chat/completions with a Bearer key — covers
    /// Gemini (compat endpoint), Groq, Mistral, local Ollama; no vendor SDK.
    /// Configuration stays the single AI section (AiOptions, env-only).
    /// </summary>
    public sealed class OpenAiChatClient(HttpClient http, IOptions<AiOptions> options)
    {
        private static readonly JsonSerializerOptions JsonOptions = new()
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        };

        public async Task<AiCallResult> CompleteAsync(
            string systemPrompt, string userPrompt, CancellationToken ct = default)
        {
            var ai = options.Value;
            if (!ai.IsConfigured)
            {
                return new AiCallResult(AiCallStatus.NotConfigured, null,
                    "KI-Anbieter ist nicht konfiguriert (AI__BaseUrl / AI__ApiKey / AI__Model).");
            }

            var payload = new ChatRequest(
                Model: ai.Model!,
                Messages:
                [
                    new ChatMessage("system", systemPrompt),
                    new ChatMessage("user", userPrompt),
                ],
                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 AiCallResult(AiCallStatus.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 AiCallResult(AiCallStatus.UpstreamError, null,
                        "KI-Antwort enthielt keinen Text.")
                    : new AiCallResult(AiCallStatus.Ok, text);
            }
            catch (Exception ex) when (ex is HttpRequestException or TaskCanceledException or JsonException)
            {
                return new AiCallResult(AiCallStatus.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);
    }
}
