using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using PdfSharpCore.Drawing;
using PdfSharpCore.Pdf;
using PdfSharpCore.Pdf.IO;

namespace GestionaDenuncias.Shared.Helpers
{
    public static class PdfHelper
    {
        private const double ReportTextMarginLeft = 95;
        private const double ReportPdfSignatureGutter = 70;
        private const double ReportPdfRightMargin = 20;

        /// <summary>
        /// Fusiona varios ficheros (PDF, imágenes, TXT) en un único PDF.
        /// Los .txt se renderizan con márgenes iguales, alineación a la izquierda y ajuste de líneas,
        /// preservando líneas en blanco.
        /// </summary>
        /// <param name="files">Secuencia de tuplas (FileName, ContentBytes)</param>
        /// <returns>Bytes del PDF combinado</returns>
        public static byte[] MergeFilesToPdf(IEnumerable<(string FileName, byte[] Content)> files)
            => MergeFilesToPdf(files, textMarginLeft: 40, insetPdfPagesForSignature: false);

        public static byte[] MergeReportToPdf(IEnumerable<(string FileName, byte[] Content)> files)
            => MergeFilesToPdf(
                files,
                textMarginLeft: ReportTextMarginLeft,
                insetPdfPagesForSignature: true);

        private static byte[] MergeFilesToPdf(
            IEnumerable<(string FileName, byte[] Content)> files,
            double textMarginLeft,
            bool insetPdfPagesForSignature)
        {
            if (files == null) throw new ArgumentNullException(nameof(files));

            var outputDoc = new PdfDocument();

            foreach (var (fileName, content) in files)
            {
                if (string.IsNullOrEmpty(fileName) || content == null || content.Length == 0)
                    throw new InvalidOperationException($"El archivo '{fileName}' no tiene contenido.");

                var ext = Path.GetExtension(fileName).ToLowerInvariant();
                switch (ext)
                {
                    case ".pdf":
                        using (var src = PdfReader.Open(new MemoryStream(content), PdfDocumentOpenMode.Import))
                        {
                            foreach (var page in src.Pages)
                            {
                                var importedPage = outputDoc.AddPage(page);
                                if (insetPdfPagesForSignature)
                                {
                                    InsetPdfPageForSignature(importedPage);
                                }
                            }
                        }
                        break;

                    case ".jpg":
                    case ".jpeg":
                    case ".png":
                    case ".gif":
                        using (var img = XImage.FromStream(() => new MemoryStream(content)))
                        {
                            var page = outputDoc.AddPage();
                            page.Width = XUnit.FromPoint(img.PointWidth);
                            page.Height = XUnit.FromPoint(img.PointHeight);
                            using var gfxImg = XGraphics.FromPdfPage(page);
                            gfxImg.DrawImage(img, 0, 0, page.Width, page.Height);
                        }
                        break;

                    case ".txt":
                        // Renderizado de TXT con margen y ajuste de líneas, preservando líneas en blanco
                        var text = Encoding.UTF8.GetString(content);
                        PdfPage pageTxt = outputDoc.AddPage();
                        XGraphics gfxTxt = XGraphics.FromPdfPage(pageTxt);

                        var marginLeft = textMarginLeft;
                        const double marginRight = 40;
                        const double marginTop = 40;
                        const double marginBottom = 40;
                        var font = new XFont("Courier New", 10, XFontStyle.Regular);
                        var sample = gfxTxt.MeasureString("Ay", font);
                        var lineHeight = sample.Height * 1.2;

                        double y = marginTop;
                        double pageWidth = pageTxt.Width.Point;
                        double pageHeight = pageTxt.Height.Point;
                        double maxWidth = pageWidth - marginLeft - marginRight;

                        foreach (var origLine in text.Replace("\r\n", "\n").Replace('\r', '\n').Split('\n'))
                        {
                            // Línea en blanco: preservarla
                            if (string.IsNullOrWhiteSpace(origLine))
                            {
                                y += lineHeight;
                                if (y + lineHeight > pageHeight - marginBottom)
                                {
                                    gfxTxt.Dispose();
                                    pageTxt = outputDoc.AddPage();
                                    gfxTxt = XGraphics.FromPdfPage(pageTxt);
                                    y = marginTop;
                                }
                                continue;
                            }

                            var words = origLine.Split(' ');
                            string currentLine = string.Empty;

                            foreach (var word in words)
                            {
                                var testLine = string.IsNullOrEmpty(currentLine) ? word : currentLine + " " + word;
                                var size = gfxTxt.MeasureString(testLine, font);
                                if (size.Width <= maxWidth)
                                {
                                    currentLine = testLine;
                                }
                                else
                                {
                                    // Dibujar la línea acumulada
                                    gfxTxt.DrawString(
                                        currentLine,
                                        font,
                                        XBrushes.Black,
                                        new XRect(marginLeft, y, maxWidth, lineHeight),
                                        XStringFormats.TopLeft);
                                    y += lineHeight;
                                    currentLine = word;

                                    // Paginación si se sale por abajo
                                    if (y + lineHeight > pageHeight - marginBottom)
                                    {
                                        gfxTxt.Dispose();
                                        pageTxt = outputDoc.AddPage();
                                        gfxTxt = XGraphics.FromPdfPage(pageTxt);
                                        y = marginTop;
                                    }
                                }
                            }

                            // Dibujar la última línea del párrafo
                            if (!string.IsNullOrEmpty(currentLine))
                            {
                                gfxTxt.DrawString(
                                    currentLine,
                                    font,
                                    XBrushes.Black,
                                    new XRect(marginLeft, y, maxWidth, lineHeight),
                                    XStringFormats.TopLeft);
                                y += lineHeight;

                                if (y + lineHeight > pageHeight - marginBottom)
                                {
                                    gfxTxt.Dispose();
                                    pageTxt = outputDoc.AddPage();
                                    gfxTxt = XGraphics.FromPdfPage(pageTxt);
                                    y = marginTop;
                                }
                            }
                        }

                        gfxTxt.Dispose();
                        break;

                    default:
                        throw new NotSupportedException($"Extensión no soportada: {ext}");
                }
            }

            using var ms = new MemoryStream();
            outputDoc.Save(ms);
            return ms.ToArray();
        }

        private static void InsetPdfPageForSignature(PdfPage page)
        {
            var pageWidth = page.Width.Point;
            var availableWidth = Math.Max(1, pageWidth - ReportPdfSignatureGutter - ReportPdfRightMargin);
            var scaleX = Math.Min(1, availableWidth / pageWidth);

            var command = string.Create(
                CultureInfo.InvariantCulture,
                $"q {scaleX:0.#####} 0 0 1 {ReportPdfSignatureGutter:0.#####} 0 cm\n");

            var prepend = page.Contents.PrependContent();
            prepend.Stream = prepend.CreateStream(Encoding.ASCII.GetBytes(command));

            var append = page.Contents.AppendContent();
            append.Stream = append.CreateStream(Encoding.ASCII.GetBytes("\nQ\n"));
        }



    }
}
