using Services.Fooocus;
using Services.Models;
using Services.Ollama;
using Services.Whisper;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using ToolsServices;
using Models;

namespace Services.ReActAgent
{
    #region Classe ReActAgent
    public class ReActAgent
    {
        #region Variables
        
        //private readonly eTypeDocument TypeDocument;
        //private readonly OnnxEmbeddingGenerator _embedder;
        //private readonly VectorStore _vectorStore = new();
        //private readonly VectorStoreNew _vectorStoreNew;// = new(TypeDocument);
        
        private string MessageErreur = "";

        private readonly List<(string role, string message)> _history = new();

        // Taille max en caractères par chunk (à adapter selon ton modèle LLM)
        private const int MaxChunkLength = 3000;
        #endregion

        #region Constructeur
        /*
        public ReActAgent(eTypeDocument typeDocument, bool isChargerVecteurs=true)
        {
            LoggerService.LogInfo("ReActAgent");

            _embedder = new();
            TypeDocument = typeDocument;
            // inclus le chargement des vecteurs enregistrés
            if(isChargerVecteurs)
                _vectorStoreNew = new(TypeDocument);
            else
                _vectorStoreNew = new(eTypeDocument.None);

        }
        */
        public ReActAgent()
        {
            LoggerService.LogInfo("ReActAgent");
        }        
        #endregion

        #region Méthodes publiques

        #region RAG

        /*
        public string SearchOld(string query)
        {
            LoggerService.LogInfo("ReActAgent.Search");
            StringBuilder sb = new();

            float[] queryEmbedding = _embedder.GenerateEmbedding(query);
            var results = _vectorStoreNew.Search(queryEmbedding);
            LoggerService.LogDebug("");
            LoggerService.LogDebug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            LoggerService.LogDebug($"Nouvelle recherche : {query}");
            LoggerService.LogDebug("------");

            foreach (var entry in results)
            {
                LoggerService.LogDebug($">>> Chunk: {entry.Chunk}...");
                LoggerService.LogDebug($">>> Document: {entry.DocumentName}");
                if(entry.EmailSubject != "")
                    LoggerService.LogDebug($">>> Email: {entry.EmailSubject}");
                LoggerService.LogDebug("------");

                //sb.AppendLine($"Chunk: {entry.Chunk.Substring(0, 120)}...");
                sb.AppendLine($"Document: {entry.DocumentName}");
                if (entry.EmailSubject != "")
                    sb.AppendLine($"Email: {entry.EmailSubject}");
                sb.AppendLine("------");
            }
            LoggerService.LogDebug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
            return sb.ToString();
        }
        */
        public async Task<(string, string)> SummarizeDocAsync(string precision, string[]? chuncks, bool isOnDemand)
        {
            LoggerService.LogInfo("ReActAgent.SummarizeAsync");
            
            var morceaux = chuncks!.ToList();

            // Optionnel : filtrer les chunks les plus pertinents via question "Résumé du document"
            // var queryVec = await _embedder.GenerateEmbedding("Résumé du document");
            // var topChunks = _vectorStore.Search(queryVec, 5);
            // string context = string.Join("\n", topChunks);

            // Ou résumer l'ensemble du document (max 3000-4000 tokens cumulés)


            string context = string.Join("\n---\n", morceaux); 
            // Le troncage se fait dans OllamaClient
            /*
            string prompt = $"""
                Tu es un assistant intelligent.

                Ta mission est de lire les extraits suivants d’un document, et d’en produire un résumé synthétique, structuré, et professionnel en moins de 100 mots.
                Ignore les mentions légales ou répétitions

                Extraits :
                {context}

                Résumé :

                """;
            */
            string prompt = PromptService.GetPrompt(PromptService.ePrompt.ReActAgent_SummarizeDoc, context);
            string? summary;
            string model = "";
            (summary, model) = await AppelerLLMAsync(ModelsUseCases.TypeUseCase.ResumeDocuments, isOnDemand, prompt, precision);
            LoggerService.LogDebug($"Résumé : {summary}");
            //_vectorStore.RemoveAllChunks();
            return (summary.Trim(), model);
        }

        public async Task<(string, string)> SummarizeIntegralLongDocAsync(string precision, string texteComplet)
        {
            LoggerService.LogInfo("ReActAgent.SummarizeIntegralLongDocAsync");
            List<string> morceaux = DecomposeText(texteComplet, MaxChunkLength); 

            var summaries = new List<string>();

            foreach (var chunk in morceaux)
            {
                /*
                string prompt = $"""
                    Tu es un assistant intelligent.

                    Ta mission est de lire les extraits suivants d’un document, et d’en produire un résumé synthétique, structuré, et professionnel en moins de 100 mots.
                    Ignore les mentions légales ou répétitions

                    Extraits :
                    {chunk}

                    Résumé :

                    """;
                */
                string prompt = PromptService.GetPrompt(PromptService.ePrompt.ReActAgent_SummarizeIntegralLongDoc, chunk);
                var (summary, _) = await AppelerLLMAsync(ModelsUseCases.TypeUseCase.ResumeDocuments, true, prompt, precision);
                summaries.Add(summary);
                //LoggerService.LogDebug($"Résumé partiel : {summary}");
            }

            // 2. Résumer tous les résumés
            //string finalSummaryPrompt = $"Voici une série de résumés partiels :\n\n{string.Join("\n\n", summaries)}\n\nFais un résumé global cohérent en moins de 500 mots.";
            string finalSummaryPrompt = PromptService.GetPrompt(PromptService.ePrompt.ReActAgent_SummarizeIntegralLongDoc_Final, string.Join("\n\n", summaries));
            var (finalSummary, model) = await AppelerLLMAsync(ModelsUseCases.TypeUseCase.ResumeDocuments, true, finalSummaryPrompt, precision);
            //LoggerService.LogDebug($"Résumé final : {finalSummary}");

            //_vectorStore.RemoveAllChunks();
            return (finalSummary, model);
        }

        //public async Task<(string, string)> RechercheRAG(string query, string precision, string model, string[]? chucks)
        public async Task<(string, string)> RechercheRAG(string query, string precision, string model, List<RankedDocument>? chucks, string domain)
        {
            LoggerService.LogInfo("ReActAgent.RechercheRAG");
            StringBuilder sb = new();
            if (chucks != null)
            {
                foreach (var c in chucks)
                {
                    //sb.AppendLine($"Document : {c.Text} (source : {c.Nom_Fichier} - score : {c.Score})");
                    sb.AppendLine($"Document : {c.Text} (source : {c.Nom_Fichier})");
                    sb.AppendLine("------");
                }
            }
            var chuncksProches = sb.ToString();
            /*
            string prompt = $"""
                Tu es un assistant spécialisé dans la lecture de documents d'entreprises.
                Le domaine professionell concerné est le suivant : {domain}

                Question : {query}

                Context :
                {chuncksProches}

                Réponds uniquement à partir du contexte. 
                Pour chaque information donnée, indique le document dont elle provient.
                Si tu n'as pas la réponse, dis que tu ne sais pas.
                
                """;
            */
            string prompt = PromptService.GetPrompt(PromptService.ePrompt.ReActAgent_RechercheRAG, query, chuncksProches, domain);
            return await AppelerLLMAsync(ModelsUseCases.TypeUseCase.RAG, true, prompt, precision, model);
        }
        #endregion

        #region LLM

        #region Requêtes à Ollama
        public static async Task<bool> IsOllamaActif(bool isOnDemand)
        {
            var precision = isOnDemand ? "OnDemand" : "Batch";
            LoggerService.LogInfo($"ReActAgent.IsOllamaActif {precision}");
            return await Services.Ollama.OllamaService.IsOllamaActif(isOnDemand);
        }

        // Appel à Ollama via EmbeddingService pour récupérer un embedding
        public async Task<(bool, float[]?)> GetEmbeddingAsync(string text, bool isOnDemand)
        {
            var precision = isOnDemand ? "OnDemand" : "Batch";
            LoggerService.LogInfo($"ReActAgent.GetEmbeddingAsync {precision}");

            return await EmbeddingService.GetEmbeddingAsync(text, isOnDemand);

            /*
            try
            {
                ParametresOllamaService? ollama = OllamaService.LoadParametres();
                if (ollama == null)
                {
                    var msg = "Erreur de chargement des paramètres Ollama.";
                    LoggerService.LogWarning(msg);
                    return (false, null);
                }
                var url = "";
                if (isOnDemand)
                    url = $"{ollama.Ollama_URL}/api/embeddings";
                else
                    url = $"{ollama.Ollama_Batch_URL}/api/embeddings";

                var request = new
                {
                    model = "nomic-embed-text",
                    prompt = text,
                    stream = false
                };
                HttpClient httpClient = new();
                var json = JsonSerializer.Serialize(request);
                var response = await httpClient.PostAsync(url,
                    new StringContent(json, Encoding.UTF8, "application/json"));

                response.EnsureSuccessStatusCode();
                var result = await response.Content.ReadAsStringAsync();

                using var doc = JsonDocument.Parse(result);
                var retour = doc.RootElement
                    .GetProperty("embedding")
                    .EnumerateArray()
                    .Select(e => e.GetSingle())
                    .ToArray();
                return (true, retour);
            }
            catch (Exception ex)
            {
                LoggerService.LogError($"Erreur lors de la récupération de l'embedding : {ex.Message}");
                return (false, null);
            }
            */
        }

        // Résumés de docs, RAG, analyse CV, analyse mails, ...
        public async Task<(string, string)> AppelerLLMAsync(ModelsUseCases.TypeUseCase useCase, bool isOnDemand, string prompt, string precision, string model = "", bool isApiExterne=false)
        {
            var precisionContext = isOnDemand ? "OnDemand" : "Batch";
            LoggerService.LogInfo($"ReActAgent.AppelerLLMAsync {precisionContext}");

            string rep = "";
            var modelDefaut = "";
            if (!isApiExterne)
            {
                // Ici, on commence par le modèle sélectionné par l'utilisateur dans l'UI (choix libre)
                // Mais s'il est dans la liste, inutile de le rappeler
                // Donc on le supprime de la liste et on le remet en premier
                var modelsDefaut = GetModelesIA(useCase).ToList();
                if(model != "")
                {
                    modelsDefaut.Remove(model);
                    modelsDefaut.Insert(0, model);
                }
                foreach (var m in modelsDefaut)
                {
                    LoggerService.LogDebug($"Appel modèle : {m}");
                    modelDefaut = m;
                    var promptFinal = prompt;
                    if (useCase == ModelsUseCases.TypeUseCase.LLM_Coder)
                    {
                        var prompt_llm_coder = PromptService.GetPrompt(PromptService.ePrompt.ReActAgent_PromptSystem_LLM_Coder);
                        promptFinal = prompt_llm_coder + "\n" + prompt;
                    }

                    var (b, s) = await Services.Ollama.OllamaService.GenererAsync(promptFinal, precision, modelDefaut, isOnDemand);
                    if (b)
                    {
                        rep = s;
                        break;
                    }
                    else
                    {
                        LoggerService.LogWarning($"Erreur modèle {m} : {s}");
                    }
                }
            }
            else
            {
                modelDefaut = "";
                rep = await AppelerAPIExterneAsync(prompt);
            }
            return (rep.Trim(),modelDefaut);
        }

        // ChatRoom
        public async Task<(string, string)> AppelerLLMAsync(ModelsUseCases.TypeUseCase useCase, string model, List<ChatMessage> messages, bool isApiExterne = false)
        {
            LoggerService.LogInfo("ReActAgent.AppelerLLMAsync");

            string rep = "";
            var modelDefaut = "";
            if (!isApiExterne)
            {
                // Ici, on commence par le modèle sélectionné par l'utilisateur dans l'UI (choix libre)
                // Mais s'il est dans la liste, inutile de le rappeler
                // Donc on le supprime de la liste et on le remet en premier
                var modelsDefaut = GetModelesIA(useCase).ToList();
                if (model != "")
                {
                    modelsDefaut.Remove(model);
                    modelsDefaut.Insert(0, model);
                }

                foreach (var m in modelsDefaut)
                {
                    LoggerService.LogDebug($"Appel modèle : {m}");
                    modelDefaut = m;
                    var (b, s) = await Services.Ollama.OllamaService.ChatAsync(modelDefaut, messages);
                    if(b)
                    {
                        rep = s;
                        break;
                    }
                    else
                    {
                        LoggerService.LogWarning($"Erreur modèle {m} : {s}");
                    }
                }
            }
            else
            {
                modelDefaut = "Api externe";
                rep = await AppelerAPIExterneAsync("", messages);
            }
            return (rep.Trim(), modelDefaut);
        }

        // Description images
        public async Task<(string, string)> AppelerLLMAsync(ModelsUseCases.TypeUseCase useCase, string model, string prompt, List<string> imagesFullFilename, bool isApiExterne = false)
        {
            LoggerService.LogInfo("ReActAgent.AppelerLLMAsync");
            var modelDefaut = "";
            string rep = "";
            if (!isApiExterne)
            {
                // Ici, on commence par le modèle sélectionné par l'utilisateur dans l'UI (choix libre)
                // Mais s'il est dans la liste, inutile de le rappeler
                // Donc on le supprime de la liste et on le remet en premier
                var modelsDefaut = GetModelesIA(useCase).ToList();
                modelsDefaut.Remove(model);
                modelsDefaut.Insert(0, model);
                foreach (var m in modelsDefaut)
                {
                    LoggerService.LogDebug($"Appel modèle : {m}");
                    modelDefaut = m;
                    var (b, s) = await Services.Ollama.OllamaService.GenererAsync(modelDefaut, prompt, imagesFullFilename);
                    if (b)
                    {
                        rep = s;
                        break;
                    }
                    else
                    {
                        LoggerService.LogWarning($"Erreur modèle {m} : {s}");
                    }
                }
            }
            else
            {
                modelDefaut = "";
                rep = await AppelerAPIExterneAsync(prompt, null, imagesFullFilename);
            }
            return (rep.Trim(), modelDefaut);
        }
        #endregion

        public async Task<List<OllamaModel>> GetInstalledModelsAsync(bool isOnDemand)
        {
            LoggerService.LogInfo("ReActAgent.GetInstalledModelsAsync");
            var rep = await Services.Ollama.OllamaService.GetInstalledModelsAsync(isOnDemand);
            return rep;
        }

        public string CleanUserInput(string input, out bool isPromptInjection)
        {
            LoggerService.LogInfo("ReActAgent.CleanUserInput");
            return Services.Ollama.OllamaService.CleanUserInput(input, out isPromptInjection);
        }

        public static ParametresOllamaService? LoadParametresOllama()
        {
            LoggerService.LogInfo("ReActAgent.LoadParametresOllama");
            return Services.Ollama.OllamaService.LoadParametres();
        }

        public static bool SaveParametresOllama(ParametresOllamaService selectedItem)
        {
            LoggerService.LogInfo("ReActAgent.SaveParametresOllama");
            return Services.Ollama.OllamaService.SaveParametres(selectedItem);
        }

        public static ParametresWhisperService? LoadParametresWhisper()
        {
            LoggerService.LogInfo("ReActAgent.LoadParametresWhisper");
            return WhisperService.LoadParametres();
        }

        public static bool SaveParametresWhisper(ParametresWhisperService selectedItem)
        {
            LoggerService.LogInfo("ReActAgent.SaveParametresWhisper");
            return WhisperService.SaveParametres(selectedItem);
        }

        public static bool SaveParametresModeles(ModelsUseCases.TypeUseCase useCase, ModelConfig models)
        {
            LoggerService.LogInfo("ReActAgent.SaveParametresModeles");
            var valueUserCase = ModelsUseCases.GetValueByEnum(useCase);
            return Services.Ollama.OllamaService.SaveParametresModeles(valueUserCase, models);
        }

        public static string GetModeleIA(ModelsUseCases.TypeUseCase useCase)
        {
            LoggerService.LogInfo("ReActAgent.GetModeleIA");
            var valueUseCase = ModelsUseCases.GetValueByEnum(useCase);
            return Services.Ollama.OllamaService.GetModeleIA(valueUseCase);
        }

        public static IEnumerable<string> GetModelesIA(ModelsUseCases.TypeUseCase useCase)
        {
            LoggerService.LogInfo("ReActAgent.GetModelesIA");
            var valueUserCase = ModelsUseCases.GetValueByEnum(useCase);
            return Services.Ollama.OllamaService.GetModelesIA(valueUserCase);
        }
        #endregion

        #region Fooocus
        #region Requêtes à Fooocus
        public static async Task<bool> IsFooocusActif()
        {
            LoggerService.LogInfo("ReActAgent.IsFooocusActif");
            return await FooocusService.IsFooocusActif();
        }

        public async Task<(string, string)> GenerateTextToImage(ModelsUseCases.TypeUseCase useCase, string query, string model, bool isWithAssistant, bool isGenerateParametres)
        {
            try
            {
                LoggerService.LogInfo($"ReActAgent.GenerateImage : {query}");

                var promptFinal = query;
                if (isWithAssistant)
                {
                    LoggerService.LogDebug($"isWithAssistant : {model}");
                    // TODO V2 : l'assistant IA doit générer les paramètres Fooocus en + du prompt
                    if (isGenerateParametres)
                    {
                        var lstStyles = await GetFooocusStylesAsync();
                        var strStyles = string.Join(", ", lstStyles);

                        string prompt1 = PromptService.GetPrompt(PromptService.ePrompt.ReActAgent_GenerateImage, query);

                        var (promptOllama,_) = await AppelerLLMAsync(useCase, true, prompt1, "GenerateImage - génération prompt", model);
                        LoggerService.LogDebug($"Ollama Prompt V2 - prompt : {promptOllama}");

                        string prompt2 = PromptService.GetPrompt(PromptService.ePrompt.ReActAgent_GenerateImageV2, promptOllama, strStyles);


                        var (parametres,_) = await AppelerLLMAsync(useCase, true, prompt2, "GenerateImageV2 - génération paramètres", model);
                        LoggerService.LogDebug($"Ollama Prompt V2 - paramètres : {parametres}");

                        var request = JsonSerializer.Deserialize<FooocusRequest_Text_to_Image>(parametres);
                        
                        if (request == null)
                        {
                            LoggerService.LogWarning($"request est null : {parametres}");
                            return ($"request est null : {parametres}", model);
                        }

                        // Maintenant on vérifie que les styles proposés existent bien
                        request!.style_selections = request.style_selections
                            .Where(s => lstStyles.Contains(s, StringComparer.OrdinalIgnoreCase))
                            .ToArray();

                        var isStylesPerso = false;
                        if(request!.style_selections.Length == 0)
                        {
                            isStylesPerso = true;
                            var requestBody = FooocusService.LoadParametresFooocus();
                            request!.style_selections = requestBody.style_selections;
                            if(request!.style_selections.Length == 0)
                            {
                                isStylesPerso = false;
                                request!.style_selections.Append("MRE Dark Cyberpunk");
                            }
                        }

                        // Injection du prompt généré par assistant IA
                        request!.prompt = promptOllama;
                        // On force quelques paramètres
                        request!.aspect_ratios_selection = "1152*896";

                        string imagePath = await FooocusService.GenerateImageWithFooocus(request);

                        if (promptOllama.Contains("Erreur"))
                        {
                            LoggerService.LogWarning($"{promptOllama} / {imagePath}");
                            return ($"{promptOllama} / {imagePath}", model);
                        }
                        else if (parametres.Contains("Erreur"))
                        {
                            LoggerService.LogWarning($"{parametres} / {imagePath}");
                            return ($"{parametres} / {imagePath}", model);
                        }
                        else
                        {
                            var txt = "";
                            if (isStylesPerso)
                                txt = ", vos styles ont été appliqués";
                            LoggerService.LogDebug($"{imagePath}{txt}");
                            return ($"{imagePath}", model);
                        }
                    }
                    else
                    {
                        /*
                        string prompt = $"""
                            Transforme cette idée en prompt détaillé pour générer une image avec Fooocus : {query}                
                            """;
                        */
                        string prompt = PromptService.GetPrompt(PromptService.ePrompt.ReActAgent_GenerateImage, query);
                        (promptFinal,_) = await AppelerLLMAsync(useCase, true, prompt, "GenerateImage", model);
                        LoggerService.LogDebug($"Ollama Prompt : {promptFinal}");

                        string imagePath = await FooocusService.GenerateImageWithFooocus(promptFinal);
                        if (promptFinal.Contains("Erreur"))
                        {
                            LoggerService.LogDebug($"{promptFinal} / {imagePath}");
                            return ($"{promptFinal} / {imagePath}",model);
                        }
                        else
                        {
                            LoggerService.LogDebug($"{imagePath}");
                            return ($"{imagePath}",model);
                        }
                    }
                }
                else
                {
                    string imagePath = await FooocusService.GenerateImageWithFooocus(promptFinal);
                    if (imagePath.Contains("Erreur") || imagePath.Contains("Error"))
                    {
                        LoggerService.LogDebug($"Erreur : {imagePath}");
                        return ($"Erreur : {imagePath}",model);
                    }
                    else
                    {
                        LoggerService.LogDebug($"{imagePath}");
                        return ($"{imagePath}",model);
                    }
                }
            }

            catch (Exception ex)
            {
                LoggerService.LogError($"ReActAgent.GenerateImage Erreur : {ex.Message}");
                return await GenerateTextToImage(useCase, query, model, isWithAssistant, false);
            }
        }

        public async Task<(string, string)> GenerateTextToImageWithIP(ModelsUseCases.TypeUseCase useCase, string query, string model, bool isWithAssistant, List<string> imagesFullFilename)
        {
            LoggerService.LogInfo("ReActAgent.GenerateTextToImageWithIP");

            var promptFinal = query;
            if (isWithAssistant)
            {
                string prompt = PromptService.GetPrompt(PromptService.ePrompt.ReActAgent_GenerateImage, query);
                (promptFinal,_) = await AppelerLLMAsync(useCase, true, prompt, "GenerateImage", model);
                LoggerService.LogDebug($"Ollama Prompt : {promptFinal}");
            }
            var rep = await (FooocusService.GenerateTextToImageWithIP(promptFinal, imagesFullFilename));
            return (rep, model);
        }
        #endregion

        public (string, string, string) LoadParametresGenerateImg()
        {
            LoggerService.LogInfo("ReActAgent.LoadParametresGenerateImg");
            return FooocusService.LoadParametresGenerateImg();
        }

        public bool SaveParametresGenerateImg(string url, string endpointv1, string endpointv2)
        {
            LoggerService.LogInfo("ReActAgent.SaveParametresGenerateImg");
            return FooocusService.SaveParametresGenerateImg(url, endpointv1, endpointv2);

        }

        public FooocusRequest_Text_to_Image LoadParametresFooocus()
        {
            LoggerService.LogInfo("ReActAgent.LoadParametresFooocus");
            return FooocusService.LoadParametresFooocus();
        }

        public bool SaveParametresFooocus(FooocusRequest_Text_to_Image param, List<string> ListeSelectedsStylesFooocus)
        {
            LoggerService.LogInfo("ReActAgent.SaveParametresFooocus");
            return FooocusService.SaveParametresFooocus(param, ListeSelectedsStylesFooocus);
        }

        public async Task<List<string>> GetFooocusStylesAsync()
        {
            LoggerService.LogInfo("ReActAgent.GetFooocusStylesAsync");
            return await FooocusService.GetFooocusStylesAsync();
        }
        #endregion

        #region Whisper
        public static async Task<bool> IsWhisperActif()
        {
            LoggerService.LogInfo("ReActAgent.IsWhisperActif");
            return await WhisperService.IsWhisperActif();
        }

        public async Task<(bool, string)> TranscribeAudio(string fullFileName)
        {
            LoggerService.LogInfo("ReActAgent.IsTranscribeAudio");
            return await WhisperService.TranscribeAudio(fullFileName);
        }
        #endregion

        #endregion

        #region Méthodes privées
        private List<string> DecomposeText(string texte, int tailleMax)
        {
            LoggerService.LogInfo("ReActAgent.DecomposeText");
            var chunks = new List<string>();

            int position = 0;
            while (position < texte.Length)
            {
                int longueur = Math.Min(tailleMax, texte.Length - position);

                // On limite le startIndex pour LastIndexOf
                int rechercheMax = Math.Min(position + longueur, texte.Length - 1);

                // Recherche du dernier point avant la limite
                int coupure = texte.LastIndexOf('.', rechercheMax);

                if (coupure <= position || coupure == -1)
                    coupure = position + longueur;

                // Sécurité pour éviter de dépasser la fin
                int longueurChunk = Math.Min(coupure - position + 1, texte.Length - position);
                string chunk = texte.Substring(position, longueurChunk).Trim();

                chunks.Add(chunk);
                position = coupure + 1;
            }

            return chunks;
        }

        private async Task<string> AppelerAPIExterneAsync(string prompt = "", List<ChatMessage>? messages = null, List<string>? imagesFullFilename = null)
        {
            LoggerService.LogInfo("ReActRagAgent.AppelerAPIExterneAsync");
            try
            {
                string NomFichierData = FichiersInternesService.ParamsApiExterne;
                string apiKey = "";
                string url = "";
                string model = "";
                if (File.Exists(NomFichierData))
                {
                    string[] lignes = File.ReadAllLines(NomFichierData);
                    if (lignes.Length > 0)
                        apiKey = lignes[0];

                    if (lignes.Length > 1)
                        url = lignes[1];

                    if (lignes.Length > 2)
                        model = lignes[2];
                }
                else
                {
                    apiKey = "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";
                    url = "https://api.openai.com/v1/chat/completions";
                    model = "gpt-4.1-mini";// gpt-4.1";  //gpt-4o-mini //gpt-4.1-mini
                }

                // Envoyer à l’API externe
                string reponse = await CallApiExterneAsync(apiKey, url, model, prompt, messages = null, imagesFullFilename);

                return reponse;
            }
            catch (Exception ex)
            {
                MessageErreur += "\n" + ex.Message;
                LoggerService.LogError($"Erreur lors de l'appel à l'API externe : {ex.Message}");
                return MessageErreur;
            }
        }

        private async Task<string> CallApiExterneAsync(string apiKey, string url, string model, string prompt = "", List<ChatMessage>? messages = null, List<string>? imagesFullFilename = null)
        {
            LoggerService.LogInfo($"ReActRagAgent.CallApiExterneAsync : {model}");
            try
            {
                var imagesBase64 = new StringBuilder();
                if (imagesFullFilename != null)
                {
                    foreach (var uneImage in imagesFullFilename)
                    {
                        byte[] imageBytes = File.ReadAllBytes(uneImage);
                        imagesBase64.AppendLine($"data:image/png;base64,{Convert.ToBase64String(imageBytes)}");
                    }
                }


                using var client = new HttpClient();
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
                StringContent? content;

                if (imagesFullFilename != null)
                {
                    var body = new
                    {
                        model = model,
                        messages = new[]
                        {
                            new { role = "system", content = "Tu es un assistant qui répond en langue française." },
                            new { role = "user", content = prompt },
                            new { role = "user", content = imagesBase64.ToString() }
                        },
                        temperature = 0.0
                    };
                    content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");

                }
                else if (messages != null)
                {
                    var systemPrompt = new ChatMessage { Role = "system", Content = "Tu dois toujours répondre en langue française." };
                    var allMessages = new List<ChatMessage> { systemPrompt };
                    allMessages.AddRange(messages);

                    var body = new
                    {
                        model = model,
                        messages = allMessages.Select(m => new { role = m.Role, content = m.Content }).ToList(),
                        temperature = 0.0
                    };
                    content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");

                }
                else
                {
                    var body = new
                    {
                        model = model,
                        messages = new[]
                        {
                            new { role = "system", content = "Tu es un assistant qui répond en langue française." },
                            new { role = "user", content = prompt }
                        },
                        temperature = 0.0
                    };
                    content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");

                }


                //var content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
                var response = await client.PostAsync(url, content);
                var json = await response.Content.ReadAsStringAsync();

                if (!response.IsSuccessStatusCode)
                {

                    using JsonDocument errorDoc = JsonDocument.Parse(json);
                    var error = errorDoc.RootElement.GetProperty("error");
                    string message = error.GetProperty("message").GetString()!;
                    string type = error.GetProperty("type").GetString()!;

                    MessageErreur += "\n" + $"External API Error ({type}): {message}";
                    return "";
                }



                using JsonDocument doc = JsonDocument.Parse(json);
                var rep = doc.RootElement
                             .GetProperty("choices")[0]
                             .GetProperty("message")
                             .GetProperty("content")
                             .GetString();

                return model + " : " + rep!;
            }

            catch (Exception ex)
            {
                MessageErreur += "\n" + ex.Message;
                LoggerService.LogError($"Erreur lors de l'appel à l'API externe : {ex.Message}");
                return "";
            }
        }
        #endregion
    }
    #endregion
}
