using LAPS_XMLQC_Service.Models;
using LAPS_XMLQC_Service.Services;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using Microsoft.AspNetCore.Authorization;

namespace LAPS_XMLQC_Service.Controllers.RegexReplace
{
    [Route("api/[controller]")]
    [ApiController]
    public class RegexReplaceApiController : ControllerBase
    {
        private readonly RegexPatternService _regexPatternService;
        private readonly FileSearchService _fileSearchService;

        public RegexReplaceApiController(RegexPatternService regexPatternService, FileSearchService fileSearchService)
        {
            _regexPatternService = regexPatternService;
            _fileSearchService = fileSearchService;
        }

        [Authorize]
        [HttpGet("GetPatterns")]
        public IActionResult GetPatterns()
        {
            var patterns = _regexPatternService.GetRegexPatterns();
            return Ok(patterns);
        }

        [Authorize]
        [HttpPost("Search")]
        public async Task<IActionResult> PerformSearch([FromBody] SearchRequest request)
        {
            var results = await _fileSearchService.SearchFiles(request.DirectoryPath, request.SearchTerm, request.FileType, request.CaseInsensitive, request.SingleLine, request.MultiLine, request.IgnoreWhitespace, request.ExplicitCapture);
            return Ok(results);
        }

        [Authorize]
        [HttpPost("Preview")]
        public async Task<IActionResult> PreviewChanges([FromBody] SearchRequest request)
        {
            var results = await _fileSearchService.PreviewOrReplaceAll(request.DirectoryPath, request.SearchTerm, request.ReplacementText, request.FileType, request.CaseInsensitive, request.SingleLine, request.MultiLine, request.IgnoreWhitespace, request.ExplicitCapture, "Preview");
            return Ok(results);
        }

        [Authorize]
        [HttpPost("ReplaceAll")]
        public async Task<IActionResult> ReplaceAllChanges([FromBody] SearchRequest request)
        {
            var results = await _fileSearchService.PreviewOrReplaceAll(request.DirectoryPath, request.SearchTerm, request.ReplacementText, request.FileType, request.CaseInsensitive, request.SingleLine, request.MultiLine, request.IgnoreWhitespace, request.ExplicitCapture, "ReplaceAll");
            return Ok(results);
        }

        [Authorize]
        [HttpPost("Apply")]
        public async Task<IActionResult> ApplyChanges([FromBody] MatchedResult results)
        {
            if (results == null)
            {
                return BadRequest("No changes provided to apply.");
            }

            try
            {
                results = await _fileSearchService.ApplyChange(results);
                return Ok(results);
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"An error occurred while applying changes: {ex.Message}");
            }
        }

        [Authorize]
        [HttpPost("Accept")]
        public IActionResult Accept([FromBody] List<MatchedResult> results)
        {
            if (results == null)
            {
                return BadRequest("No changes provided to apply.");
            }

            try
            {
                results = _fileSearchService.Accept(results);
                return Ok(results);              
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"An error occurred while applying changes: {ex.Message}");
            }
        }

        [Authorize]
        [HttpPost("Reject")]
        public IActionResult Reject([FromBody] List<MatchedResult> results)
        {
            if (results == null)
            {
                return BadRequest("No changes provided to apply.");
            }

            try
            {
                results = _fileSearchService.Reject(results);
                return Ok(results);
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"An error occurred while applying changes: {ex.Message}");
            }
        }

        [Authorize]
        [HttpPost("Upload")]
        public async Task<IActionResult> UploadFiles([FromForm] UploadRequest request)
        {
            var results = new List<MatchedResult>();

            if (request?.Files == null || request.Files.Count == 0)
            {
                return BadRequest("No files were uploaded.");
            }

            string fileExtension = request.FileType.Replace("*", string.Empty);
            if (string.IsNullOrWhiteSpace(fileExtension))
            {
                return BadRequest("Invalid file type specified.");
            }

            // Limit the number of concurrent tasks
            int maxDegreeOfParallelism = 5; // Adjust this value based on your server's capabilities
            var semaphore = new SemaphoreSlim(maxDegreeOfParallelism);

            var tasks = request.Files.Select(async file =>
            {
                await semaphore.WaitAsync(); // Limit concurrent execution

                try
                {
                    // Check if the file's extension matches the requested file type
                    if (!Path.GetExtension(file.FileName).Equals(fileExtension, StringComparison.OrdinalIgnoreCase))
                    {
                        return null; // Skip files that don't match the extension
                    }

                    using var stream = new MemoryStream();
                    await file.CopyToAsync(stream);
                    var content = System.Text.Encoding.UTF8.GetString(stream.ToArray());

                    // Perform regex search on the file content
                    var matches = await _fileSearchService.SearchContent(content, request.SearchTerm,
                                                                         request.CaseInsensitive, request.SingleLine,
                                                                         request.MultiLine, request.IgnoreWhitespace, request.ExplicitCapture);

                    // Calculate the total result count across all pattern results
                    int resultCount = matches.Sum(patternResult => patternResult.Matches!.Count);


                    return new MatchedResult
                    {
                        FileName = file.FileName,
                        Content = content,
                        PatternResults = matches,
                        ResultCount = resultCount
                    };
                }
                catch
                {
                    // Log the error (or handle it as needed)
                    // Return null to indicate an error for this file
                    return null;
                }
                finally
                {
                    semaphore.Release(); // Release the semaphore for the next task
                }
            });

            // Await all the tasks and filter out any null results
            var taskResults = await Task.WhenAll(tasks);
            results = taskResults.Where(result => result != null).Cast<MatchedResult>().ToList();

            return Ok(results);
        }
        
    }
}
