using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace WikipediaRagWinForms.Services
{
    public class OllamaClient
    {
        private static readonly HttpClient _httpClient = new HttpClient
        {
            Timeout = Timeout.InfiniteTimeSpan
        };

        private readonly string _baseUrl;
        private readonly string _model;

        public OllamaClient(string baseUrl, string model)
        {
            _baseUrl = baseUrl.TrimEnd('/');
            _model = model;

            // --- Ollama-Server automatisch starten ---
            EnsureOllamaRunning();
        }

        private void EnsureOllamaRunning()
        {
            // Prüfen, ob ollama bereits läuft
            var processes = System.Diagnostics.Process.GetProcessesByName("ollama");
            if (processes.Length > 0)
                return;

            // Starten: ollama serve
            var psi = new System.Diagnostics.ProcessStartInfo
            {
                FileName = "ollama",
                Arguments = "serve",
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardOutput = false,
                RedirectStandardError = false
            };

            System.Diagnostics.Process.Start(psi);
        }

        // =====================================================================
        // 1) Klassischer Aufruf – wird vom Moderator und der Titelsuche genutzt
        // =====================================================================
        public async Task<string> GenerateAsync(string prompt, CancellationToken cancellationToken)
        {
            var url = _baseUrl + "/generate";

            var payload = new
            {
                model = _model,
                prompt = prompt,
                stream = false,
                options = new Dictionary<string, object>
                {
                    { "temperature", 0.2 },
                    { "num_predict", 200 }
                }
            };

            string json = JsonConvert.SerializeObject(payload);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            using (var response = await _httpClient.PostAsync(url, content, cancellationToken))
            {
                response.EnsureSuccessStatusCode();
                string responseJson = await response.Content.ReadAsStringAsync();

                var ollamaResponse = JsonConvert.DeserializeObject<OllamaGenerateResponse>(responseJson);
                return ollamaResponse?.response ?? "";
            }
        }

        // =====================================================================
        // 2) Streaming-Aufruf – für live Token-by-Token Ausgabe in der UI
        // =====================================================================
        public async Task<string> GenerateStreamAsync(
    string prompt,
    Action<string> onToken,
    CancellationToken cancellationToken)
        {
            var url = _baseUrl + "/generate";

            var payload = new
            {
                model = _model,
                prompt = prompt,
                stream = true,
                options = new Dictionary<string, object>
        {
            { "temperature", 0.2 },
            { "num_predict", 200 }
        }
            };

            string json = JsonConvert.SerializeObject(payload);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            using (var response = await _httpClient.PostAsync(url, content, cancellationToken))
            {
                response.EnsureSuccessStatusCode();

                using (var stream = await response.Content.ReadAsStreamAsync())
                using (var reader = new StreamReader(stream))
                {
                    StringBuilder sb = new StringBuilder();
                    bool lastWasBullet = false;

                    string line;
                    while ((line = await reader.ReadLineAsync()) != null)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        if (!line.StartsWith("{"))
                            continue;

                        var obj = JsonConvert.DeserializeObject<OllamaGenerateResponse>(line);
                        if (obj?.response == null)
                            continue;

                        string tok = obj.response;

                        // --- Bulletpunkt-Spezialbehandlung ---
                        if (tok == "•")
                        {
                            // Neue Zeile erzwingen – aber nur wenn wir nicht direkt vor einem Bullet sind
                            string nl = sb.Length > 0 && !lastWasBullet ? "\r\n" : "";

                            sb.Append(nl);
                            sb.Append("• ");
                            onToken(nl + "• ");

                            lastWasBullet = true;
                            continue;
                        }

                        lastWasBullet = false;

                        // --- Normaler Token, unverändert ausgeben ---
                        sb.Append(tok);
                        onToken(tok);

                        if (obj.done)
                            break;
                    }

                    return sb.ToString();
                }
            }
        }



        private class OllamaGenerateResponse
        {
            public string model { get; set; }
            public string response { get; set; }
            public bool done { get; set; }
        }

        private class OllamaEmbeddingResponse
        {
            public List<float> embedding { get; set; }
        }

        public async Task<List<float>> GetEmbeddingAsync(string text, CancellationToken cancellationToken)
        {
            var url = _baseUrl + "/embeddings";

            var payload = new
            {
                model = _model,
                input = text
            };

            string json = JsonConvert.SerializeObject(payload);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            using (var response = await _httpClient.PostAsync(url, content, cancellationToken))
            {
                response.EnsureSuccessStatusCode();
                string responseJson = await response.Content.ReadAsStringAsync();

                var obj = JsonConvert.DeserializeObject<OllamaEmbeddingResponse>(responseJson);
                return obj?.embedding ?? new List<float>();
            }
        }
    }
}
