using System.IO;
using TSpdf.Kernel.Pdf;
using TSpdf.Kernel.Utils;
using TSpdf.Pdfa;

namespace tsPDFUtilsCore
{
    public class Utilidades
    {
        public static MemoryStream crearPDFA(Stream pdfOrigen)
        {
            var reader = new PdfReader(pdfOrigen);
            MemoryStream ms = new MemoryStream();

            var writerProps = new WriterProperties();
            writerProps.SetPdfVersion(PdfVersion.PDF_2_0);
            writerProps.UseSmartMode();
            var writer = new PdfWriter(ms, writerProps);
            writer.SetSmartMode(true);

            // Necesario para que el memoryStream no se cierre, y no de una execpción donde se llame a la función
            writer.SetCloseStream(false);

            var sourcePDF = new PdfDocument(reader);

           bool esRGB =  recorrerPaginas(sourcePDF);

            // Se recorre las páginas para comprobar que no falte la anotación F, en tal caso la mete
            for (int page = 1; page <= sourcePDF.GetNumberOfPages(); page++)
            {
                var paginaActual = sourcePDF.GetPage(page);
                var anotaciones = paginaActual.GetAnnotations();

                if (anotaciones != null)
                {
                    foreach (var anotacionActual in anotaciones)
                    {
                        var diccionario = anotacionActual.GetPdfObject();

                        if (!diccionario.ContainsKey(PdfName.F))
                        {
                            diccionario.Put(PdfName.F, new PdfNumber(4));
                        }
                    }
                }
            }

            PdfADocument disPDF;

            if (esRGB)
            {
                disPDF = new PdfADocument(writer, PdfAConformanceLevel.PDF_A_3B, new PdfOutputIntent("Custom"
           , "", "https://www.color.org", "sRGB", new MemoryStream(Properties.Resources.sRGB2014)));
            }
            else
            {
                disPDF = new PdfADocument(writer, PdfAConformanceLevel.PDF_A_3B, new PdfOutputIntent("Custom"
              , "", "https://www.color.org", "FOGRA39", new MemoryStream(Properties.Resources.fogra39L)));

            }

            disPDF.InitializeOutlines();

            // Configurar parámetros requeridos
            disPDF.SetTagged();
            disPDF.GetCatalog().SetLang(new PdfString("es-ES"));
            disPDF.GetCatalog().SetViewerPreferences(new PdfViewerPreferences().SetDisplayDocTitle(true));

            var merger = new PdfMerger(disPDF, true,true);
            merger.Merge(sourcePDF, 1, sourcePDF.GetNumberOfPages());


            sourcePDF.Close();
            disPDF.Close();
            reader.Close();
            writer.Close();

            // Esto hace falta para volver al inicio del memorystream
            ms.Position = 0;

            return ms;
        }

        static bool controlarInterpolate(PdfDictionary resources, bool tieneRGB)
        {

            var xObjects = resources?.GetAsDictionary(PdfName.XObject);
            bool tieneRGBActual = tieneRGB;

            foreach (var key in xObjects.KeySet())
            {
                var stream = xObjects.GetAsStream(key);

                // se mira que tenga el prefijo subtype qye es la forma como el pdf pone las imagenes y los formularios -> /Subtype /Image   ó /Subtype /Form
                var subtype = stream.GetAsName(PdfName.Subtype);

                // En caso de que sea una imagen, pone el interpolate a false, que es lo que causaba el fallo en alguno de los pdfs
                if (PdfName.Image.Equals(subtype))
                {
                    if (stream.GetAsBoolean(PdfName.Interpolate)?.GetValue() == true)
                    {
                        stream.Put(PdfName.Interpolate, PdfBoolean.FALSE);
                    }

                    // Detectar RGB
                    var colorSpace = stream.Get(PdfName.ColorSpace);

                    if (colorSpace != null && colorSpace.Equals(PdfName.DeviceRGB))
                    {
                        tieneRGBActual = true;
                        tieneRGB = true;
                    }

                }

                // En caso de que sea un formulario, vuelve a llamar al metodo para buscar imagenes dentro
                else if (PdfName.Form.Equals(subtype))
                {
                    var formRes = stream.GetAsDictionary(PdfName.Resources);
                    if (formRes != null)
                    {
                        bool hijoTieneRGB = controlarInterpolate(formRes, tieneRGBActual);

                        if (hijoTieneRGB)
                        {
                            tieneRGBActual = true;
                        }
                    }
                }

            }

            return tieneRGBActual;
        }

        static bool recorrerPaginas(PdfDocument pdf)
        {
            bool tieneRGB = false;

            for (int i = 1; i <= pdf.GetNumberOfPages(); i++)
            {
                bool rgbMinimo = false;

                var diccPaginaActual = pdf.GetPage(i).GetResources().GetPdfObject();
                rgbMinimo = controlarInterpolate(diccPaginaActual, tieneRGB);

                if (rgbMinimo)
                {
                    tieneRGB = true;
                }
            }

            return tieneRGB;
        }


    }
}
