using System.Text.RegularExpressions;
using LAPS_XMLQC_Service.Models;
//using SystemRegexMatch = System.Text.RegularExpressions.Match;
using MyMatch = LAPS_XMLQC_Service.Models.Matches;
using System.Collections.Generic;
using System.Threading.Tasks;
//using System.Threading;
using System.IO;
using System.Linq;
using System;
using System.Collections.Concurrent;
//using Microsoft.AspNetCore.Mvc;

namespace LAPS_XMLQC_Service.Services
{
    public class FileSearchService : FileSearchServiceBase
    {
        private readonly RegexPatternService _regexPatternService;
        public enum Status
        {
            Load,
            Preview,
            Accept,
            Replaced,
            Failed,
            Deleted
        }
        public FileSearchService(RegexPatternService regexPatternService)
        {
            _regexPatternService = regexPatternService;        
        }
        public async Task<List<MatchedResult>> SearchFiles(string directoryPath, string? searchTerm, string fileType, bool caseInsensitive, bool singleLine, bool multiLine, bool ignoreWhitespace, bool explicitCapture)
        {
            var regexOptions = RegexOptions.None;
            var results = new ConcurrentBag<MatchedResult>();

            if (caseInsensitive) regexOptions |= RegexOptions.IgnoreCase;
            if (singleLine) regexOptions |= RegexOptions.Singleline;
            if (multiLine) regexOptions |= RegexOptions.Multiline;
            if (ignoreWhitespace) regexOptions |= RegexOptions.IgnorePatternWhitespace;
            if (explicitCapture) regexOptions |= RegexOptions.ExplicitCapture;

            regexOptions |= RegexOptions.Compiled;

            var patterns = _regexPatternService.GetRegexPatterns();
            var files = Directory.GetFiles(directoryPath, fileType, SearchOption.AllDirectories);

            var tasks = patterns.Select(pattern => Task.Run(async () =>
            {
                var searchTerm = pattern.Pattern;
                var regex = new Regex(searchTerm, regexOptions);

                var fileTasks = files.Select(async file =>
                {
                    var content = await File.ReadAllTextAsync(file);
                    content = content.Replace("<COURTCASE>", "<COURTCASE xmlns:lndocmeta=\"http://www.lexis-nexis.com/lndocmeta\" xmlns:docinfo=\"http://www.lexis-nexis.com/glp/docinfo\" xmlns:lnvxe=\"http://www.lexis-nexis.com/lnvx\" xmlns:lnv=\"http://www.lexis-nexis.com/lnv\">");
                    var matches = regex.Matches(content);

                    if (matches.Count > 0)
                   {
                        results.Add(new MatchedResult
                        {
                            FileName = Path.GetFileName(file),
                            FilePath = file,
                            DirectoryPath = directoryPath,
                            Content = content,
                            PreviewContent = "",
                            ResultCount = matches.Count,
                            FinalContent = "",
                            Status = Status.Load.ToString(),
                            PatternResults = new List<PatternResult>
                            {
                                new PatternResult
                                {
                                    Pattern = searchTerm,
                                    Matches = matches
                                        .Select(m => new MyMatch
                                        {
                                            Index = m.Index,
                                            Content = m.Value,
                                            LineNumber = CalculateLineNumber(content, m.Index)
                                        }).ToList()
                                }
                            }
                        });
                    }
                });

                await Task.WhenAll(fileTasks);
            }));

            await Task.WhenAll(tasks);

            return results.ToList();


            //var regexOptions = RegexOptions.None;
            //var results = new List<MatchedResult>();

            //if (caseInsensitive) regexOptions |= RegexOptions.IgnoreCase;
            //if (singleLine) regexOptions |= RegexOptions.Singleline;
            //if (multiLine) regexOptions |= RegexOptions.Multiline;
            //if (ignoreWhitespace) regexOptions |= RegexOptions.IgnorePatternWhitespace;
            //if (explicitCapture) regexOptions |= RegexOptions.ExplicitCapture;

            //regexOptions |= RegexOptions.Compiled;

            //var patterns = _regexPatternService.GetRegexPatterns();

            //var files = Directory.GetFiles(directoryPath, fileType, SearchOption.AllDirectories);

            //foreach (var pattern in patterns)
            //{
            //    searchTerm = pattern.Pattern;

            //    var regex = new Regex(searchTerm, regexOptions);

            //    foreach (var file in files)
            //    {
            //        var content = await File.ReadAllTextAsync(file);
            //        var matches = regex.Matches(content);

            //        if (matches.Count > 0)
            //        {
            //            results.Add(new MatchedResult
            //            {
            //                FileName = Path.GetFileName(file),
            //                FilePath = file,
            //                DirectoryPath = directoryPath,
            //                Content = content,
            //                PreviewContent = "",
            //                ResultCount = matches.Count,
            //                FinalContent = "",
            //                Status = Status.Load.ToString(),
            //                PatternResults = new List<PatternResult>
            //                {
            //                    new PatternResult
            //                    {
            //                        Pattern = searchTerm,
            //                        Matches = matches
            //                            .Select(m => new MyMatch
            //                            {
            //                                Index = m.Index,
            //                                Content = m.Value,
            //                                LineNumber = CalculateLineNumber(content, m.Index)
            //                            }).ToList()
            //                    }
            //                }
            //            });
            //        }
            //    }

            //}           

            //return results;

            //// Validate and format the file type
            //if (fileType.StartsWith('.'))
            //{
            //    fileType = "*" + fileType;
            //}
            //else if (!fileType.StartsWith('*') && !fileType.StartsWith('.'))
            //{
            //    fileType = "*." + fileType;
            //}

            //var results = new List<MatchedResult>();

            //Regex? regex = null;

            //if (!string.IsNullOrEmpty(searchTerm))
            //{
            //    var regexOptions = RegexOptions.None;

            //    // Set regex options based on parameters
            //    if (caseInsensitive)
            //        regexOptions |= RegexOptions.IgnoreCase;

            //    if (singleLine)
            //        regexOptions |= RegexOptions.Singleline;

            //    if (multiLine)
            //        regexOptions |= RegexOptions.Multiline;

            //    if (ignoreWhitespace)
            //        regexOptions |= RegexOptions.IgnorePatternWhitespace;

            //    if (explicitCapture)
            //        regexOptions |= RegexOptions.ExplicitCapture;

            //    regexOptions |= RegexOptions.Compiled;

            //    regex = new Regex(searchTerm, regexOptions);
            //}

            //// Limit the degree of parallelism for better resource management
            //int maxDegreeOfParallelism = 5;
            //var semaphore = new SemaphoreSlim(maxDegreeOfParallelism);

            //var fileTasks = Directory.GetFiles(directoryPath, fileType, SearchOption.AllDirectories)
            //                         .Select(async file =>
            //                         {
            //                             await semaphore.WaitAsync();
            //                             try
            //                             {
            //                                 var matches = new List<MyMatch>();
            //                                 var content = await File.ReadAllTextAsync(file);

            //                                 var matchedResult = new MatchedResult
            //                                 {
            //                                     FileName = Path.GetFileName(file),
            //                                     Content = content,
            //                                     PatternResults = new List<PatternResult>()
            //                                 };

            //                                 // Perform regex matching on the file content

            //                                 if (regex != null)
            //                                 {
            //                                     foreach (SystemRegexMatch match in regex!.Matches(content))
            //                                     {
            //                                         matches.Add(new MyMatch
            //                                         {
            //                                             Index = match.Index,
            //                                             Content = match.Value,
            //                                             LineNumber = CalculateLineNumber(content, match.Index)
            //                                         });
            //                                     }
            //                                 }


            //                                 // Add the pattern result
            //                                 var patternResult = new PatternResult { Pattern = searchTerm, Matches = matches };

            //                                 matchedResult.ResultCount = matches.Count;
            //                                 matchedResult.PatternResults!.Add(patternResult);

            //                                 return matchedResult;
            //                             }
            //                             catch (Exception ex)
            //                             {
            //                                 // Handle the exception, possibly logging it
            //                                 Console.WriteLine($"Error processing file {file}: {ex.Message}");
            //                                 return null;
            //                             }
            //                             finally
            //                             {
            //                                 semaphore.Release(); // Release the semaphore
            //                             }
            //                         });

            //// Execute all file processing tasks in parallel
            //var taskResults = await Task.WhenAll(fileTasks);
            //results = taskResults.Where(result => result != null).Cast<MatchedResult>().ToList();

            //return results;
        }

        public async Task<List<MatchedResult>> PreviewOrReplaceAll(string directoryPath, string? searchTerm, string replacementText, string fileType, bool caseInsensitive, bool singleLine, bool multiLine, bool ignoreWhitespace, bool explicitCapture, string options)
        {

            // Configure regex options
            if (string.IsNullOrEmpty(searchTerm))
                throw new ArgumentException("Search term cannot be empty.");

            // Configure regex options
            if (string.IsNullOrEmpty(replacementText))
                throw new ArgumentException("Replacement text cannot be empty.");

            var regexOptions = RegexOptions.None;

            if (caseInsensitive) regexOptions |= RegexOptions.IgnoreCase;
            if (singleLine) regexOptions |= RegexOptions.Singleline;
            if (multiLine) regexOptions |= RegexOptions.Multiline;
            if (ignoreWhitespace) regexOptions |= RegexOptions.IgnorePatternWhitespace;
            if (explicitCapture) regexOptions |= RegexOptions.ExplicitCapture;

            //  regexOptions |= RegexOptions.Compiled;

            var results = new List<MatchedResult>();

            try
            {
                var regex = new Regex(searchTerm, regexOptions);
           

            

            
            var files = Directory.GetFiles(directoryPath, fileType, SearchOption.AllDirectories);

            foreach (var file in files)
            {
                var content = await File.ReadAllTextAsync(file);
                  //  content = content.Replace("<COURTCASE>", "<COURTCASE xmlns:lndocmeta=\"http://www.lexis-nexis.com/lndocmeta\" xmlns:docinfo=\"http://www.lexis-nexis.com/glp/docinfo\" xmlns:lnvxe=\"http://www.lexis-nexis.com/lnvx\" xmlns:lnv=\"http://www.lexis-nexis.com/lnv\">");

                    var matches = regex.Matches(content);                 

                // Generate preview
                var previewContent = regex.Replace(content, replacementText);

                  MatchCollection match= regex.Matches(previewContent);

                if (matches.Count > 0)
                {
                    results.Add(new MatchedResult
                    {
                        FileName = Path.GetFileName(file),
                        FilePath = file,
                        DirectoryPath = directoryPath,
                        Content = content,
                        PreviewContent = previewContent,
                        ResultCount = matches.Count,
                        FinalContent = "",
                        Status = Status.Preview.ToString(),
                        PatternResults = new List<PatternResult>
                        {
                            new PatternResult
                            {
                                Pattern = searchTerm,
                                Matches = matches
                                    .Select(m => new MyMatch
                                    {
                                        Index = m.Index,
                                        Content = m.Value,
                                        LineNumber = CalculateLineNumber(content, m.Index)
                                    }).ToList()
                            }
                        }
                    });
                }
            }

            if(options.Equals("ReplaceAll"))
            {
                results = await ApplyChanges(results);
            }

            }
            catch (Exception ex)
            {

            }

            return results;
        }

        public async Task<MatchedResult> ApplyChange(MatchedResult result)
        {
            string filePath = string.Empty;

            if (!string.IsNullOrEmpty(result.PreviewContent))
            {
                //string outputDirectory = Path.Combine(Path.GetDirectoryName(result.FilePath), "OUT");

                //if (!Directory.Exists(outputDirectory))
                //{
                //    Directory.CreateDirectory(outputDirectory); // Creates the folder if it doesn't exist       
                //}                         

                // Set the file path within the "out" folder
                //filePath = Path.Combine(outputDirectory, Path.GetFileName(result.FilePath));

                string outputDirectory = result.DirectoryPath.Replace(@"\IN", @"\OUT");

                filePath = Path.Combine(outputDirectory, Path.GetFileName(result.FilePath));

                // Write the preview content to the file
                await File.WriteAllTextAsync(filePath, result.PreviewContent);

                result.OutputFilePath = filePath;

                result.Status = Status.Accept.ToString();
            }

            // Return the result
            return result;

            // string filePath = string.Empty;
            // if (!string.IsNullOrEmpty(result.PreviewContent))
            // {

            //     filePath = result.FilePath;                
            //     await File.WriteAllTextAsync(filePath, result.PreviewContent); // Write the preview content to the file
            //    // Update the final content
            //   // result.FinalContent = result.PreviewContent;
            //   // result.Content = result.PreviewContent;
            //   // result.PreviewContent = "";
            //    result.Status = "Replaced";
            //}            
            //return result;
        }

        public async Task<List<MatchedResult>> ApplyChanges(List<MatchedResult> results)
        {
            string filePath = string.Empty;
            string outputDirectory = string.Empty;
            foreach (var result in results)
            {
                if (!string.IsNullOrEmpty(result.PreviewContent))
                {
                    //string outputDirectory = Path.Combine(Path.GetDirectoryName(result.FilePath), "OUT");

                    //if (!Directory.Exists(outputDirectory))
                    //{
                    //    Directory.CreateDirectory(outputDirectory); // Creates the folder if it doesn't exist       
                    //}

                    //// Set the file path within the "out" folder
                    //filePath = Path.Combine(outputDirectory, Path.GetFileName(result.FilePath));

                    if (string.IsNullOrEmpty(outputDirectory))
                    {
                        outputDirectory = result.DirectoryPath.Replace(@"\IN", @"\OUT");
                    }                    

                    filePath = Path.Combine(outputDirectory, Path.GetFileName(result.FilePath));

                    // Write the preview content to the file
                    await File.WriteAllTextAsync(filePath, result.PreviewContent);

                    result.OutputFilePath = filePath;

                    result.Status = Status.Accept.ToString();
                }
            }
            return results;
            //string filePath = string.Empty;
            //foreach (var result in results)
            //{
            //    if (!string.IsNullOrEmpty(result.PreviewContent))
            //    {                    
            //        filePath = string.Empty;
            //        filePath = result.FilePath;
            //        await File.WriteAllTextAsync(filePath, result.PreviewContent); // Write the preview content to the file
            //        // Update the final content
            //        //result.FinalContent = result.PreviewContent;
            //       // result.Content = result.PreviewContent;
            //       // result.PreviewContent = "";
            //        result.Status = "Replaced";
            //    }
            //}
            //return results;
        }

        public List<MatchedResult> Accept(List<MatchedResult> results)
        {           
            foreach (var result in results)
            {
                try
                {
                    // Move file and overwrite if it exists
                    File.Move(result.OutputFilePath, result.FilePath, true);
                    result.FinalContent = result.PreviewContent;
                    result.Content = result.PreviewContent;             
                    result.Status = Status.Replaced.ToString();
                }
                catch (Exception ex)
                {
                    // Log the error and update the status to indicate failure
                    Console.WriteLine($"Error processing file {result.OutputFilePath}: {ex.Message}");
                    result.Status = Status.Failed.ToString();
                }
            }
            return results;
        }

        public List<MatchedResult> Reject(List<MatchedResult> results)
        {
            foreach (var result in results)
            {
                try
                {
                    File.Delete(result.OutputFilePath);  
                    result.Status = Status.Deleted.ToString();
                }
                catch (Exception ex)
                {
                    // Log the error and update the status to indicate failure
                    Console.WriteLine($"Error processing file {result.OutputFilePath}: {ex.Message}");
                    result.Status = Status.Failed.ToString();
                }
            }
            return results;
        }

    }
}
