using Services.Fooocus;
using Services.Models;
using Services.ReActAgent;
using System.Text.Json;
using ToolsServices;
using static Services.ReActAgent.ModelsUseCases;

namespace Services
{
    public static class ChatService
    {
        #region Variables
        private static string Folder => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Conversations");
        private static Services.ReActAgent.ReActAgent _ReActAagent = new();
        #endregion

        #region Constructeur
        static ChatService()
        {
            LoggerService.LogInfo($"ChatService");
            try
            {
                if (!Directory.Exists(Folder))
                {
                    LoggerService.LogDebug($"ChatService : tentative de création du dossier de conversations : {Folder}");
                    Directory.CreateDirectory(Folder);
                    LoggerService.LogInfo($"ChatService : dossier de conversations créé : {Folder}");
                }
            }
            catch (Exception ex)
            {
                LoggerService.LogError($"ChatService : Erreur : {ex.Message}");
            }
        }
        #endregion

        #region Méthodes publiques
        public static string GetModeleIA(ModelsUseCases.TypeUseCase useCase)
        {
            return ReActAgent.ReActAgent.GetModeleIA(useCase);
        }
        
        public static IEnumerable<string> GetModelesIA(ModelsUseCases.TypeUseCase useCase)
        {
            return ReActAgent.ReActAgent.GetModelesIA(useCase);
        }
        
        public static async Task<List<string>> GetFooocusStylesAsync()
        {
            return await _ReActAagent.GetFooocusStylesAsync();
        }

        public static (string, string, string) LoadParametresGenerateImg()
        {
            return _ReActAagent.LoadParametresGenerateImg();
        }

        public static bool SaveParametresGenerateImg(string url, string endpointV1, string endpointv2)
        {
            return _ReActAagent.SaveParametresGenerateImg(url, endpointV1, endpointv2);
        }

        public static FooocusRequest_Text_to_Image LoadParametresFooocus()
        {
            return _ReActAagent.LoadParametresFooocus();
        }

        public static bool SaveParametresFooocus(FooocusRequest_Text_to_Image param, List<string> ListeSelectedsStylesFooocus)
        {
            return _ReActAagent.SaveParametresFooocus(param, ListeSelectedsStylesFooocus);
        }

        public static void SaveConversation(ChatConversation conv)
        {
            LoggerService.LogInfo($"ChatService.Save");

            Directory.CreateDirectory(Folder);
            var path = Path.Combine(Folder, conv.Id + ".json");
            File.WriteAllText(path, JsonSerializer.Serialize(conv, new JsonSerializerOptions { WriteIndented = true }));
        }

        public static void Delete(string conversationId)
        {
            LoggerService.LogInfo($"ChatService.Delete");
            var path = Path.Combine(Folder, conversationId + ".json");
            if (File.Exists(path)) File.Delete(path);
        }
        
        public static List<ChatConversation> LoadAll(string type)
        {
            LoggerService.LogInfo($"ChatService.LoadAll");

            return Directory.GetFiles(Folder, "*.json")
                            .Select(file => JsonSerializer.Deserialize<ChatConversation>(File.ReadAllText(file)))
                            .Where(c => c != null)
                            .Where(c=>c.Type == type)
                            .Cast<ChatConversation>()
                            .ToList();
        }

        public static async Task<(bool, string, string)> SendMessageAsync(ModelsUseCases.TypeUseCase useCase, List<ChatMessage> messages, string model, bool isApiExterne=false)
        {
            LoggerService.LogInfo($"ChatService.SendMessageAsync");
            var (s,m) = await _ReActAagent.AppelerLLMAsync(useCase, model, messages, isApiExterne);
            return (true, s, m);
        }
        
        public static async Task<(bool, string, string)> SendMessageAsync(string message, string model, bool isWithAssistant, bool isGenerateParametres)
        {
            LoggerService.LogInfo($"ChatService.SendMessageAsync");
            var (s,m) = await _ReActAagent.GenerateTextToImage(ModelsUseCases.TypeUseCase.PromptGenerationFooocus,  message, model, isWithAssistant, isGenerateParametres);
            return (true, s, m);
        }

        public static async Task<(bool, string, string)> SendMessageAsync(string message, string model, bool isWithAssistant, List<string> documentsFullFilename)
        {
            LoggerService.LogInfo($"ChatService.SendMessageAsync");
            var (s,m) = await _ReActAagent.GenerateTextToImageWithIP(ModelsUseCases.TypeUseCase.PromptGenerationFooocus, message, model, isWithAssistant, documentsFullFilename);
            return (true, s, m);
        }

        public static async Task<(bool, string, string)> SendMessageAsync(ModelsUseCases.TypeUseCase useCase, string prompt, string model, List<string> documentsFullFilename, bool isApiExterne = false)
        {
            if (useCase == TypeUseCase.LLM)
            {
                var (b1,s11,s12) = await SendMessageLLMAsync(prompt, model, documentsFullFilename, isApiExterne);
                List<ChatMessage> messages = new();
                prompt = prompt + "\n" + s11;
                var userMessage = new ChatMessage { Role = "user", Content = prompt, Model = model };
                messages.Add(userMessage);

                var (b2, s21, s22) = await SendMessageAsync(ModelsUseCases.TypeUseCase.LLM, messages, model, isApiExterne);
                return (b1 && b2, "Résumé\n------: \n" + s11 + "\n------\nFin du résumé\n\n" + s21, "Résumé : " + s12 + "\n" + "Traitement de la demande : " + s22);
            }
            else if (useCase == TypeUseCase.LLM_Coder)
            {
                return await SendMessageLLMCoderAsync(prompt, model, documentsFullFilename, isApiExterne);
            }
            else
            {
                return (false, "Erreur : Cas d'usage qui n'est ni LLM, ni LLM Coder", model);
            }
            

        }
        #endregion

        #region Méthodes privées

        private static async Task<(bool, string, string)> SendMessageLLMAsync(string prompt, string model, List<string> documentsFullFilename, bool isApiExterne = false)
        {
            (List<string> lstImages, List<string> lstDocuments) = FilesService.GetListesFichiers(documentsFullFilename);

            // Images mais pas de documents
            if (lstImages.Count > 0 && lstDocuments.Count == 0)
            {
                LoggerService.LogInfo($"ChatService.SendMessageLLMAsync : {lstImages.Count} image(s) mais pas de documents");
                var (s, m) = await _ReActAagent.AppelerLLMAsync(ModelsUseCases.TypeUseCase.InterpretationImages, model, prompt, lstImages, isApiExterne);
                return (true, s, m);
            }
            // Documents mais pas d'image
            else if (lstImages.Count == 0 && lstDocuments.Count > 0)
            {
                LoggerService.LogInfo($"ChatService.SendMessageLLMAsync : {lstDocuments.Count} document(s) mais pas d'image");
                var (resume, m) = await GetResume(lstDocuments);
                return (true, resume.ToString(), m);
            }
            // Images + documents
            else
            {
                LoggerService.LogInfo($"ChatService.SendMessageLLMAsync :  {lstImages.Count} image(s) +  {lstDocuments.Count} document(s)");
                var resume = await GetResume(lstDocuments);
                var (reponse, m) = await _ReActAagent.AppelerLLMAsync(ModelsUseCases.TypeUseCase.InterpretationImages, model, prompt, lstImages, isApiExterne);
                return (true, resume + "\n\n" + reponse, m);
            }
        }

        private static async Task<(bool, string, string)> SendMessageLLMCoderAsync(string prompt, string model, List<string> documentsFullFilename, bool isApiExterne = false)
        {
            (List<string> lstImages, List<string> lstDocuments) = FilesService.GetListesFichiers(documentsFullFilename);

            // Images non prises en compte dans ce contexte
            if (lstImages.Count > 0 && lstDocuments.Count == 0)
            {
                LoggerService.LogDebug($"ChatService.SendMessageLLMCoderAsync : {lstImages.Count} image(s) mais pas de documents : pas pris en compte");
                return (false, "Erreur : les images ne sont prises en compte dans ce contexte", model);
            }
            // Documents pris en compte
            else if (lstDocuments.Count > 0)
            {
                LoggerService.LogInfo($"ChatService.SendMessageLLMCoderAsync : {lstDocuments.Count} document(s)");
                var codeDocs = "";
                foreach (var doc in lstDocuments)
                {
                    var code = $"{Path.GetFileName(doc)} : \n" + TxtService.ExtractTextFromTxt(doc);
                    codeDocs += "\n" + code;
                }
                var (rep, m) = await _ReActAagent.AppelerLLMAsync(ModelsUseCases.TypeUseCase.LLM_Coder, true, prompt + "\n\n" + codeDocs, "Analyse de code", model, isApiExterne);
                return (true, rep, m);
            }
            // cas qui ne devrait pas arriver
            else
            {
                LoggerService.LogInfo($"ChatService.SendMessageLLMCoderAsync :  {lstImages.Count} image(s) +  {lstDocuments.Count} document(s)");
                return (true, "Cas qui ne devrait pas arriver", model);
            }
        }

        private static async Task<(string, string)> GetResume(List<string> lstDocuments)
        {
            LoggerService.LogInfo($"ChatService.GetResume");
            string resumes = "";
            string model = "";
            foreach (var doc in lstDocuments)
            {
                var filename = System.IO.Path.GetFileName(doc);
                string content = FilesService.ExtractText(doc);
                //agent.IngestDocument(content, doc);
            

                var (resume, m) = await _ReActAagent.SummarizeIntegralLongDocAsync("ChatRoom", content);
                resumes += "\n\n" + filename + " : \n" + resume;
                model = m;
            }
            return (resumes, model);
        }

        public static async Task<List<OllamaModel>> GetInstalledModelsAsync()
        {
            var models = await _ReActAagent.GetInstalledModelsAsync(true);
            return models;
        }
        #endregion
    }
}