using MbeSoap;
using PDFtoPrinter;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using System.Xml.Serialization;
using static System.Drawing.Printing.PrinterSettings;

namespace WK5.Core
{
    [SupportedOSPlatform("windows")]
    public static class Printer
    {
        public const string DefaultPrinter = @"\\SRV01\KyoceraP3045dn";
        public const string DefaultLabelPrinter = @"\\SRV01\ZD420-Lager";


        /// <summary>
        /// Druckt eine PDF auf den angegebenen Drucker
        /// </summary>
        /// <param name="file"></param>
        /// <param name="druckername"></param>
        /// <returns></returns>
        public static async Task<PrintResponse> PrintAsync(string file, string druckername)
        {
            try
            {
                var printer = new PDFtoPrinterPrinter();
                await printer.Print(new PrintingOptions(druckername, file));
                return new PrintResponse
                {
                    Message = "Erfolgreich gedruckt",
                    Success = true
                };
            }
            catch (Exception ex)
            {
                return new PrintResponse
                {
                    Message = ex.Message,
                    Success = false
                };
            }
        }





        /// <summary>
        /// Schickt ein Image Objekt an den angegebenen Drucker. Wenn kein Drucker angegeben ist, wird es an den Default Drucker gesendet
        /// </summary>
        /// <param name="img">Ein Objekt der Klasse <see cref="Image"/> das gedruckt werden soll</param>
        /// <param name="printer">Optional: Der Drucker auf dem das Bild gedruckt werden soll</param>
        /// <returns>Gibt ein Objekt der Struktur <see cref="PrintResponse"/> zurück das Daten über den Druckauftrag enthält</returns>
        public static PrintResponse Print(Image img, string? printer = null)
        {
            if (String.IsNullOrWhiteSpace(printer))
            {
                printer = Printer.DefaultPrinter;
            }

            PrinterSettings settings = new PrinterSettings
            {
                PrinterName = printer
            };
            PaperSizeCollection ps = settings.PaperSizes;

            try
            {
                using PrintDocument doc = new PrintDocument
                {
                    PrinterSettings = settings
                };

                // Zum debuggen der Druckereinstellungen
                /*var (success, data, message) = KarleyLibrary.Serialization.XMLWriter.Serialize(doc.DefaultPageSettings);
                File.WriteAllText(Path.Combine(GlobalConfig.OutputPfadWK5, "print_log.xml"), data);*/
                doc.PrintPage += (_, ev) =>
                {
                    ev.Graphics?.DrawImage(img, ev.PageBounds);
                };

                doc.Print();
            }
            catch (Exception ex)
            {
                return new PrintResponse(false, ex.Message);
            }

            return new PrintResponse(true, "");
        }

        /// <summary>
        /// Kovnertiert ein Byte Array zu einem Image und sendet es an den Drucker. Wenn kein Drucker angegeben ist, wird es an den Default Drucker gesendet.
        /// </summary>
        /// <param name="bytes">Ein Byte Array das zu einem Bild konvertiert und an den Drucker gesendet werden soll</param>
        /// <param name="printer"></param>
        /// <returns>Gibt ein Objekt der Struktur <see cref="PrintResponse"/> zurück das Daten über den Druckauftrag enthält</returns>
        public static PrintResponse Print(byte[] bytes, string? printer = null)
        {
            if (String.IsNullOrWhiteSpace(printer))
            {
                printer = Printer.DefaultPrinter;
            }

            MemoryStream stream = new MemoryStream(bytes);

            Image img = Image.FromStream(stream);

            return Print(img, printer);
        }

        /// <summary>
        /// Konvertiert einen Base64 string in ein Image und druckt dieses auf dem angegebenene Drucker. Sollte keine Drucker angegeben sein, wird auf dem Default Drucker gedruckt.
        /// </summary>
        /// <param name="base64">Der Base64 String der konvertiert werden soll</param>
        /// <param name="printer">Optional: Der Drucker auf dem gedruckt werden soll</param>
        /// <returns>Gibt ein Objekt der Struktur <see cref="PrintResponse"/> zurück was Daten über den Druckauftrag enthält</returns>
        public static PrintResponse PrintBase64(string base64, string? printer = null)
        {
            if (String.IsNullOrWhiteSpace(printer))
            {
                printer = Printer.DefaultPrinter;
            }

            byte[] bytes = Convert.FromBase64String(base64);
            return Printer.Print(bytes, printer);
        }

        public static void PrintLabel(LabelType label)
        {
            Printer.Print(label.Stream, DefaultLabelPrinter);
        }

        public static void PrintLabel(string base64Label)
        {
            Printer.PrintBase64(base64Label, DefaultLabelPrinter);
        }
        public static IEnumerable<string> GetPrinters()
        {
            foreach (string printer in PrinterSettings.InstalledPrinters)
            {
                yield return printer;
            }
        }
    }

    public struct PrintResponse
    {
        public bool Success { get; set; }
        public string Message { get; set; }
        public PrintResponse(bool _success, string _message)
        {
            this.Success = _success;
            this.Message = _message;
        }
    }
}
