using Microsoft.AspNetCore.Mvc;
using PSTW_CentralSystem.DBContext;
using PSTW_CentralSystem.Areas.MMS.Models.PDFGenerator;
using QuestPDF.Fluent;
using Microsoft.EntityFrameworkCore;
using MySqlConnector;

namespace PSTW_CentralSystem.Areas.MMS.Controllers
{
    public class TarballPdfDto //data transfer object, only holds data, used to move data between programs
    {
        // From tbl_marine_tarball
        public int Id { get; set; }
        public required string StationID { get; set; }
        public required string Longitude { get; set; }
        public required string Latitude { get; set; }
        public required DateTime DateSample { get; set; }
        public required TimeSpan TimeSample { get; set; }
        public required string ClassifyID { get; set; }
        public string? OptionalName1 { get; set; }
        public string? OptionalName2 { get; set; }
        public string? OptionalName3 { get; set; }
        public string? OptionalName4 { get; set; }
        public required string FirstSampler { get; set; }

        // From joined tables
        public required string LocationName { get; set; }  // From tbl_marine_station
        public required string StateName { get; set; }     // From tbl_state
        public required string FullName { get; set; }      // From tbl_user
        public required string LevelName { get; set; }     // From tbl_level
    }

    [Area("MMS")]
    public class MarineController : Controller
    {
        private readonly MMSSystemContext _context;//Used in TarBallForm and GeneratePdfResponse to query the database.
        private readonly NetworkShareAccess _networkAccessService;//used in GetImage and GeneratePdfResponse
        private const string PhotoBasePath = @"\\192.168.12.42\images\marine\manual_tarball";//used in GetImage and GeneratePdfResponse

        public MarineController(MMSSystemContext context, NetworkShareAccess networkAccessService)
        {
            _context = context;
            _networkAccessService = networkAccessService;
        }

        public IActionResult Index()
        {
            return View();
        }

        public async Task<IActionResult> TarBallForm()//make it async in case of traffic/frequent usage
        {
            try
            {
                var marineTarballs = await _context.MarineTarballs
                    .Select(t => new
                    {
                        id = t.Id,
                        date = t.DateSample.ToString("yyyy/MM/dd"),
                        station = t.StationID,
                        time = t.TimeSample.ToString("hh\\:mm\\:ss")
                    })
                    .ToListAsync();

                Console.WriteLine($"Marine Tarballs Count: {marineTarballs.Count}"); //???
                return View(marineTarballs);
            }
            catch (Exception ex)
            {
                return Content($"Error: {ex.Message}<br/>{ex.StackTrace}", "text/html");
            }
        }

        [HttpGet] // Explicitly mark as a GET endpoint
        public IActionResult TestCredentials()
        {
            try
            {
                // Use the EXACT same path/credentials as in Program.cs
                var testService = new NetworkShareAccess(
                    @"\\192.168.12.42\images\marine\manual_tarball",
                    "installer",
                    "mms@pstw"
                );

                testService.ConnectToNetworkPath();
                testService.DisconnectFromNetworkShare();

                return Ok("Network credentials and path are working correctly!");
            }
            catch (Exception ex)
            {
                // Log the full error (including stack trace)
                Console.WriteLine($"TestCredentials failed: {ex}");
                return StatusCode(500, $"Credentials test failed: {ex.Message}");
            }
        }
        //====================!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        public IActionResult GetImage(string fileName)
        {
            if (string.IsNullOrEmpty(fileName))
            {
                return BadRequest("Filename cannot be empty");
            }

            // Sanitize filename to prevent path traversal attacks
            var sanitizedFileName = Path.GetFileName(fileName);
            if (sanitizedFileName != fileName)
            {
                return BadRequest("Invalid filename");
            }

            int retryCount = 0;
            const int maxRetries = 3;
            bool connectionSuccess = false;

            // Retry loop for network connection
            while (retryCount < maxRetries && !connectionSuccess)
            {
                try
                {
                    Console.WriteLine($"Attempt {retryCount + 1} to connect to network share...");

                    // Connect to network share
                    _networkAccessService.ConnectToNetworkPath();
                    connectionSuccess = true;

                    Console.WriteLine("Network share connected successfully");
                }
                catch (Exception ex)
                {
                    retryCount++;
                    Console.WriteLine($"Connection attempt {retryCount} failed: {ex.Message}");

                    if (retryCount >= maxRetries)
                    {
                        Console.WriteLine($"Max connection attempts reached. Last error: {ex}");
                        return StatusCode(503, $"Could not establish connection to image server after {maxRetries} attempts");
                    }

                    // Wait before retrying (1s, 2s, 3s)
                    Thread.Sleep(1000 * retryCount);
                }
            }

            try
            {
                string imagePath = Path.Combine(PhotoBasePath, sanitizedFileName);
                Console.WriteLine($"Attempting to access image at: {imagePath}");

                // Verify file exists
                //removal TBD
                if (!System.IO.File.Exists(imagePath))
                {
                    Console.WriteLine($"Image not found at path: {imagePath}");
                    return NotFound($"Image '{sanitizedFileName}' not found on server");
                }

                // Verify file is an image
                //consider removal if/since verification already happened during image uploading (other program)
                if (!IsImageValid(imagePath))
                {
                    Console.WriteLine($"Invalid image file at path: {imagePath}");
                    return BadRequest("The requested file is not a valid image");
                }

                // Read and return the image
                byte[] imageBytes = System.IO.File.ReadAllBytes(imagePath);
                Console.WriteLine($"Successfully read image: {sanitizedFileName} ({imageBytes.Length} bytes)");

                // Determine content type based on extension
                //removal TBD??? IF image type verification already done during image uploading =========!!!!!!!!!!!
                string contentType = "image/jpeg"; // default
                string extension = Path.GetExtension(sanitizedFileName).ToLower();
                //string extension = Path.GetExtension(sanitizedFileName)?.ToLower();

                if (extension == ".png")
                {
                    contentType = "image/png";
                }
                else if (extension == ".gif")
                {
                    contentType = "image/gif";
                }

                return File(imageBytes, contentType);
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine($"Access denied to image: {ex}");
                return StatusCode(403, "Access to the image was denied");
            }
            catch (IOException ex)
            {
                Console.WriteLine($"IO error accessing image: {ex}");
                return StatusCode(503, "Error accessing image file");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Unexpected error: {ex}");
                return StatusCode(500, "An unexpected error occurred while processing the image");
            }
            finally
            {
                try
                {
                    if (connectionSuccess)
                    {
                        Console.WriteLine("Disconnecting from network share...");
                        _networkAccessService.DisconnectFromNetworkShare();
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Warning: Error disconnecting from share: {ex.Message}");
                    // Don't fail the request because of disconnect issues
                }
            }
        }

        public async Task<IActionResult> GenerateReport(int id)//calls GeneratePdfResponse to generate a PDF for inline viewing
        {
            return await GeneratePdfResponse(id, true);
        }

        public IActionResult ViewPDF(int id)
        {
            try
            {
                // Add timeout for safety
                var task = Task.Run(() => GeneratePdfResponse(id, false));
                if (task.Wait(TimeSpan.FromSeconds(30))) // 30 second timeout
                {
                    return task.Result;
                }
                return StatusCode(500, "PDF generation took too long");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"PDF VIEW ERROR: {ex}");
                return StatusCode(500, $"Error showing PDF: {ex.Message}");
            }
        }

        private async Task<IActionResult> GeneratePdfResponse(int id, bool forceDownload)
        {
            Console.WriteLine($"Requested ID in {(forceDownload ? "GenerateReport" : "ViewPDF")}: {id}");

            // Test network connection first
            try
            {
                _networkAccessService.ConnectToNetworkPath();
                _networkAccessService.DisconnectFromNetworkShare();
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Cannot access network: {ex.Message}");
            }

            try
            {
                _networkAccessService.ConnectToNetworkPath();

                // ===== 1. Get Data from Database =====
                var query = @"
                SELECT 
                    marine.*, 
                    station.LocationName, 
                    state.StateName,
                    user.FullName,
                    level.LevelName
                FROM tbl_marine_tarball marine
                JOIN tbl_marine_station station ON marine.StationID = station.StationID
                JOIN tbl_state state ON station.StateID = state.StateID
                JOIN tbl_user user ON marine.FirstSampler = user.FullName
                JOIN tbl_level level ON user.LevelID = level.LevelID
                WHERE marine.Id = @id";

                var tarball = await _context.Database
                    .SqlQueryRaw<TarballPdfDto>(query, new MySqlParameter("@id", id))
                    .FirstOrDefaultAsync();

                if (tarball == null)
                    return NotFound("Record not found");

                // Prepare boolean values for PDF 
                bool tarBallYes = tarball.ClassifyID != "NO";
                bool tarBallNo = tarball.ClassifyID == "NO";
                bool isSand = tarball.ClassifyID == "SD";
                bool isNonSandy = tarball.ClassifyID == "NS";
                bool isCoquina = tarball.ClassifyID == "CO";

                // ===== 2. Get Images =====
                // For date (stored as DATE in DB → "2025-01-30" becomes "20250130")
                var sampleDateString = tarball.DateSample.ToString("yyyyMMdd");

                // For time (stored as TIME in DB → "16:49:02" becomes "164902")
                var sampleTimeString = tarball.TimeSample.ToString("hhmmss");
                var stationFolder = Path.Combine(PhotoBasePath, tarball.StationID);

                var stationImages = new Dictionary<string, string>();
                var foundAnyImages = false;

                if (Directory.Exists(stationFolder))
                {
                    var basePattern = $"{tarball.StationID}_{sampleDateString}_{sampleTimeString}_";
                    var allImages = Directory.GetFiles(stationFolder, $"{basePattern}*");

                    foreach (var imagePath in allImages)
                    {
                        var fileName = Path.GetFileNameWithoutExtension(imagePath);
                        var type = fileName.Split('_').Last();
                        stationImages[type] = imagePath;
                        foundAnyImages = true;
                    }
                }

                if (!foundAnyImages)
                {
                    return StatusCode(404, "No images found for this record");
                }

                // Verify mandatory images exist
                var mandatoryImages = new[] {
                    "LEFTSIDECOASTALVIEW",
                    "RIGHTSIDECOASTALVIEW",
                    "DRAWINGVERTICALLINES",
                    "DRAWINGHORIZONTALLINES"
                };

                foreach (var type in mandatoryImages)
                {
                    if (!stationImages.ContainsKey(type))
                    {
                        return StatusCode(400, $"Missing mandatory image: {type}");
                    }
                }

                // ===== 3. Generate PDF =====
                var pdf = new TarBallPDF(
                    tarball.StateName,
                    tarball.StationID,
                    tarball.LocationName,
                    tarball.Longitude,
                    tarball.Latitude,
                    tarball.DateSample,
                    tarball.TimeSample,
                    tarball.ClassifyID,
                    tarBallYes,
                    tarBallNo,
                    isSand,
                    isNonSandy,
                    isCoquina,
                    stationImages["LEFTSIDECOASTALVIEW"],
                    stationImages["RIGHTSIDECOASTALVIEW"],
                    stationImages["DRAWINGVERTICALLINES"],
                    stationImages["DRAWINGHORIZONTALLINES"],
                    stationImages.GetValueOrDefault("OPTIONAL01"),
                    stationImages.GetValueOrDefault("OPTIONAL02"),
                    stationImages.GetValueOrDefault("OPTIONAL03"),
                    stationImages.GetValueOrDefault("OPTIONAL04"),
                    tarball.OptionalName1,
                    tarball.OptionalName2,
                    tarball.OptionalName3,
                    tarball.OptionalName4,
                    tarball.FirstSampler,
                    tarball.FullName,
                    tarball.LevelName
                ).GeneratePdf();

                // ===== 4. Return PDF =====
                var downloadName = $"{tarball.StationID}_{sampleDateString}_{sampleTimeString}.pdf";
                return forceDownload
                    ? File(pdf, "application/pdf", downloadName)
                    : File(pdf, "application/pdf");
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"PDF generation failed: {ex.Message}");
            }
            finally
            {
                _networkAccessService.DisconnectFromNetworkShare();
            }
        }

        private bool IsImageValid(string imagePath)
        {
            try
            {
                using (var image = System.Drawing.Image.FromFile(imagePath))
                    return true;
            }
            catch
            {
                Console.WriteLine($"Invalid image skipped: {imagePath}");
                return false;
            }
        }
    }
}
