using Services.ReActAgent;
using System.Text;
using System.Text.RegularExpressions;
using ToolsServices;

namespace Services
{
    public static class FactureService
    {
        #region Variables
        private static readonly string NomFichierParametres = FichiersInternesService.ParamsFactures;
        #endregion

        #region Méthodes publiques
        public static async Task<(bool, string)> Traitement(string inputPath, string outputPath, bool isApiExterne)
        {
            StringBuilder sb = new();
            LoggerService.LogInfo($"FactureService.Traitement");

            if (!Directory.Exists(inputPath))
            {
                LoggerService.LogWarning($"Le dossier {inputPath} n'existe pas.");
                return (false, $"Le dossier {inputPath} n'existe pas.");
            }

            if (!Directory.Exists(outputPath))
            {
                LoggerService.LogWarning($"Le dossier {outputPath} n'existe pas.");
                return (false, $"Le dossier {outputPath} n'existe pas.");
            }

            var fichiers = Directory
                            .EnumerateFiles(inputPath, "*.*", SearchOption.AllDirectories)
                            .Where(f => f.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
                            .ToArray();

            if (fichiers.Length == 0)
            {
                LoggerService.LogWarning($"Aucun fichier trouvé dans le dossier spécifié : {inputPath}");
                return (false, $"Aucun fichier trouvé dans le dossier spécifié : {inputPath}");
            }

            var reActRagAgent = new ReActAgent.ReActAgent();
            var isOk = true;
            foreach (var fichier in fichiers)
            {

                try
                {
                    #region Analyse de la facture
                    var facturePDF = FilesService.ExtractText(fichier);
                    //facturePDF = CleanPdfText(facturePDF);
                    //facturePDF = SegmentInvoice(facturePDF);

                    var prompt = PromptService.GetPrompt(PromptService.ePrompt.FactureService_AnalyserFacture_Extract, facturePDF);

                    LoggerService.LogInfo($"Traitement de facture PDF to XML : {fichier}");
                    var (reponse,m) = await reActRagAgent.AppelerLLMAsync(ModelsUseCases.TypeUseCase.Facture_To_Xml, true, prompt, "Traitement de facture PDF to XML", "", isApiExterne);

                    if (!XmlService.IsXML(reponse))
                    {
                        sb.AppendLine($"Le résultat n'est pas au format XML pour le fichier : {fichier}");
                        LoggerService.LogWarning($"Le résultat n'est pas au format XML pour le fichier : {fichier}");

                        string fileNameXML = Path.Combine(outputPath, Path.GetFileNameWithoutExtension(fichier) + ".xml");
                        TxtService.CreateTextFile(fileNameXML, reponse);
                    }
                    else
                    {
                        #region Sauvegarde du résultat
                        LoggerService.LogDebug($"Le résultat est au format XML pour le fichier : {fichier}");
                        string fileNameXML = Path.Combine(outputPath, Path.GetFileNameWithoutExtension(fichier) + ".xml");
                        TxtService.CreateTextFile(fileNameXML, reponse);
                        #endregion
                    }
                    #endregion
                }

                catch (Exception ex)
                {
                    isOk = false;
                    LoggerService.LogError($"Erreur lors de l'extraction du texte de {fichier} : {ex.Message}");
                }
            }

            LoggerService.LogInfo($"Traitement des factures PDF to XML terminée");

            return (isOk, sb.ToString());
        }

        public static (string, string) LoadParametres()
        {
            LoggerService.LogInfo("FactureService.LoadParametres");
            //ParametresOllamaService SelectedItem = new();

            try
            {
                string FicheMission = "";
                string PathCV = "";
                if (File.Exists(NomFichierParametres))
                {

                    string[] lignes = File.ReadAllLines(NomFichierParametres);

                    if (lignes.Length > 0)
                        FicheMission = lignes[0];

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

                }
                return (FicheMission, PathCV);

            }
            catch
            {
                LoggerService.LogError($"Erreur lors du chargement des paramètres depuis {NomFichierParametres}");
                return ("", "");
            }
        }

        public static bool SaveParametres(string inputPath, string outputPath)
        {
            LoggerService.LogInfo("FactureService.SaveParametres");
            try
            {
                StringBuilder sb = new();
                sb.AppendLine(inputPath);
                sb.AppendLine(outputPath);

                File.WriteAllText(NomFichierParametres, sb.ToString());

                return true;
            }
            catch
            {
                LoggerService.LogError($"Erreur lors de la sauvegarde des paramètres dans {NomFichierParametres}");
                return false;
            }

        }
        #endregion

        #region Méthodes privées
        private static string CleanPdfText(string rawText)
        {
            var text = rawText;

            // Normaliser les fins de ligne
            text = text.Replace("\r", "\n");

            // Supprimer les caractères de contrôle (sauf \n)
            text = new string(text.Where(c => !char.IsControl(c) || c == '\n').ToArray());

            // Supprimer les en-têtes et pieds de page typiques (ex: "Page 1/3", "Facture ACME", etc.)
            text = Regex.Replace(text, @"Page\s+\d+(/\d+)?", "", RegexOptions.IgnoreCase);
            text = Regex.Replace(text, @"Facture\s+n[°º]\s*\d+", "", RegexOptions.IgnoreCase);

            // Uniformiser les espaces : tabulations → espace, et espaces multiples → 1 seul
            text = Regex.Replace(text, @"[ \t]+", " ");

            // Supprimer les lignes vides excessives
            text = Regex.Replace(text, @"\n{2,}", "\n");

            // Supprimer les traits de séparation (souvent des "-----" ou "=====")
            text = Regex.Replace(text, @"[-=]{3,}", "");

            // Corriger les montants : ex "1 234,56 €" → "1234.56 EUR"
            text = Regex.Replace(text, @"(\d{1,3}(?:[ \u00A0]\d{3})*,\d{2}) ?€",
                m => m.Groups[1].Value.Replace(" ", "").Replace("\u00A0", "").Replace(",", ".") + " EUR");

            // Corriger les dates : ex "01-02-2025" → "2025-02-01"
            text = Regex.Replace(text, @"\b(\d{2})[-/](\d{2})[-/](\d{4})\b", "$3-$2-$1");

            // Fusionner les lignes coupées artificiellement (ex: "TOTAL\n123,45" → "TOTAL 123,45")
            text = Regex.Replace(text, @"([A-Za-z])\n(\d)", "$1 $2");

            // Supprimer les espaces en trop au début et fin
            text = text.Trim();

            return text;
        }

        private static string SegmentInvoice(string text)
        {
            var sb = new StringBuilder();

            // Bloc fournisseur
            var fournisseurMatch = Regex.Match(text, @"(?i)(?:fournisseur|vendor|seller).{0,50}\n(.+?)(\n|$)");
            if (fournisseurMatch.Success)
            {
                sb.AppendLine("=== FOURNISSEUR ===");
                sb.AppendLine(fournisseurMatch.Groups[1].Value.Trim());
            }

            // Bloc client
            var clientMatch = Regex.Match(text, @"(?i)(?:client|acheteur|buyer|bill to|destinataire).{0,50}\n(.+?)(\n|$)");
            if (clientMatch.Success)
            {
                sb.AppendLine("\n=== CLIENT ===");
                sb.AppendLine(clientMatch.Groups[1].Value.Trim());
            }

            // Numéro de facture
            var numeroMatch = Regex.Match(text, @"(?i)facture[^\d]*(\d+)");
            if (numeroMatch.Success)
            {
                sb.AppendLine("\n=== NUMERO FACTURE ===");
                sb.AppendLine(numeroMatch.Groups[1].Value.Trim());
            }

            // Date de facture
            var dateMatch = Regex.Match(text, @"(?i)(?:date|issued|emission)[^\d]*(\d{4}-\d{2}-\d{2})");
            if (dateMatch.Success)
            {
                sb.AppendLine("\n=== DATE FACTURE ===");
                sb.AppendLine(dateMatch.Groups[1].Value.Trim());
            }

            // Bloc lignes de facture (simplifié : cherche un tableau prix/quantité)
            var lignesMatch = Regex.Match(text, @"(?is)(description.*?total)", RegexOptions.IgnoreCase);
            if (lignesMatch.Success)
            {
                sb.AppendLine("\n=== LIGNES FACTURE ===");
                sb.AppendLine(lignesMatch.Groups[0].Value.Trim());
            }

            // Total général
            var totalMatch = Regex.Match(text, @"(?i)(total (?:ttc|general|amount)).{0,10}([\d.,]+ ?eur)");
            if (totalMatch.Success)
            {
                sb.AppendLine("\n=== TOTAL GENERAL ===");
                sb.AppendLine(totalMatch.Groups[2].Value.Trim());
            }

            // Retour du texte segmenté
            return sb.Length > 0 ? sb.ToString() : text;
        }
        #endregion

    }



}
