using KiMailOrderAgent;
using KiMailOrderAgent.Models;
using KiMailOrderAgent.Settings;
using Microsoft.Extensions.Options;
using System.Drawing;
using System.Runtime.ConstrainedExecution;
using System.Runtime.Intrinsics.X86;
using System.Text;
using System.Text.Json;
using KiMailOrderAgent.Catalog;

namespace KiMailOrderAgent.Agents;

public class OrderAgent
{
    private readonly HttpClient _httpClient;
    private readonly AgentSettings _settings;
    private readonly IArticleCatalogService _articleCatalogService;

    public OrderAgent(HttpClient httpClient, IOptions<AgentSettings> options, IArticleCatalogService articleCatalogService)
    {
        _httpClient = httpClient;
        _settings = options.Value;
        _articleCatalogService = articleCatalogService;
    }

    public async Task<ExtractedOrder?> ExtractOrderAsync(string text)
    {

        var articles = await _articleCatalogService.GetArticlesAsync(CancellationToken.None);

        var articleList = string.Join("\n", articles.Select(a =>
            $"- Artikelnummer: {a.ArticleNumber}, Name: {a.Name}, Aliase: {string.Join(", ", a.Aliases)}"
        ));

        var prompt = $$"""
             
            Du bist ein System zur Extraktion von Bestellungen.

            WICHTIG:
            - Wähle Artikel ausschließlich aus dem Artikelkatalog.
            - Wenn der Kunde eine falsche, fehlende oder unvollständige Artikelnummer nennt, korrigiere sie anhand von Name, Leistung, Beschreibung und Kontext.
            - Erfinde keine Artikelnummern.
            - Wenn kein Artikel passt, lasse "articleNumber" leer.
            - Wenn du unsicher bist, setze "confidence" unter 0.8.
            - Wenn es KEINE Bestellung ist (z. B. Anfrage, Werbung, Kontaktaufnahme), setze "isOrder": false.

            Artikelkatalog:
                {{articleList}}

            AUFGABE:
            Analysiere den Text und entscheide:
            → Ist es eine Bestellung? → isOrder = true
            → Keine Bestellung? → isOrder = false

            Gib NUR gültiges JSON zurück.
            Keine Markdown-Codeblöcke.
            Keine Erklärung.
            Kein zusätzlicher Text.

            Format:
            {
            "isOrder": true,
            "customer": {
               "companyName": "",
                "contactName": ""
            },
            "items": [
            {
            "articleNumber": "",
            "description": "",
            "quantity": 0,
            "confidence": 0.0,
            "reason": ""
            }
            ]
            }

            Wenn KEINE Bestellung:
            {
            "isOrder": false,
            "customer": {
            "companyName": "",
            "contactName": ""
            },
            "items": []
            }

            Text:
            {{text}}
            """;

        var url =
            $"https://generativelanguage.googleapis.com/v1beta/models/{_settings.Model}:generateContent";

        using var request = new HttpRequestMessage(HttpMethod.Post, url);
        request.Headers.Add("x-goog-api-key", _settings.ApiKey);

        var body = new
        {
            contents = new[]
            {
                new
                {
                    parts = new[]
                    {
                        new { text = prompt }
                    }
                }
            }
        };

        var json = JsonSerializer.Serialize(body);
        request.Content = new StringContent(json, Encoding.UTF8, "application/json");

        using var response = await _httpClient.SendAsync(request);
        var responseText = await response.Content.ReadAsStringAsync();

        if (!response.IsSuccessStatusCode)
            throw new Exception($"Gemini Fehler: {response.StatusCode} - {responseText}");

        var geminiText = ExtractTextFromGeminiResponse(responseText);

        if (string.IsNullOrWhiteSpace(geminiText))
            return null;

        geminiText = CleanJson(geminiText);

        return ParseOrder(geminiText);
    }

    private static string? ExtractTextFromGeminiResponse(string responseText)
    {
        using var doc = JsonDocument.Parse(responseText);

        if (doc.RootElement.TryGetProperty("isOrder", out var isOrderProp) &&
    isOrderProp.ValueKind == JsonValueKind.False)
        {
            return null;
        }

        return doc.RootElement
            .GetProperty("candidates")[0]
            .GetProperty("content")
            .GetProperty("parts")[0]
            .GetProperty("text")
            .GetString();
    }

    private static string CleanJson(string text)
    {
        return text
            .Replace("```json", "")
            .Replace("```", "")
            .Trim();
    }

    private static ExtractedOrder? ParseOrder(string json)
    {
        using var doc = JsonDocument.Parse(json);

        var order = new ExtractedOrder
        {
            Customer = new ExtractedCustomer
            {
                CompanyName = doc.RootElement
                    .GetProperty("customer")
                    .GetProperty("companyName")
                    .GetString(),

                ContactName = doc.RootElement
                    .GetProperty("customer")
                    .GetProperty("contactName")
                    .GetString()
            },
            Confidence = 0.90
        };

        foreach (var item in doc.RootElement.GetProperty("items").EnumerateArray())
        {
            order.Items.Add(new ExtractedOrderItem
            {
                ArticleNumber = item.GetProperty("articleNumber").GetString(),
                Description = item.GetProperty("description").GetString(),
                Quantity = item.GetProperty("quantity").GetInt32(),
                Confidence = item.TryGetProperty("confidence", out var confidence)
        ? confidence.GetDouble()
        : 0.0,
                Reason = item.TryGetProperty("reason", out var reason)
        ? reason.GetString()
        : null
            });
        }

        return order;
    }
}