
#if DEBUG
#define CREATE_PREVIEW_HTML
#endif

using iText.Html2pdf;
using KarleyLibrary.Erweiterungen;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace WK5.Core.Drucken.Briefe
{
    public sealed class PrintBrief : PrintBase
    {
        private BriefView _view;
        private BriefRegelsatz _regeln;

        private PrintBrief(BriefView view, BriefRegelsatz regeln)
        {
            _layoutFile = "Brief.html";
            _template = String.Empty;
            _regeln = regeln;
            _view = view;
        }

        /// <summary>
        /// Erstellt ein neues Objekt der <see cref="PrintBrief "/> Klasse und initialisiert dieses
        /// </summary>
        /// <param name="view">Die Daten die in den Brief eingetragen werden sollen</param>
        /// <returns>Gibt einen PrintBrief zurück</returns>
        public static async Task<PrintBrief> CreateAsync(BriefView view, BriefRegelsatz regeln)
        {
            if (view.Empfänger == null)
            {
                throw new ArgumentNullException("Es muss ein Brief Empfänger angegeben werden! #PRINT_BRIEF1");
            }

            var brief = new PrintBrief(view, regeln);

            await brief.InitializeAsync();
            return brief;
        }

        /// <summary>
        /// Generiert sich einen passenden Namen zu einer Datei in einem Speicherpfad der noch nicht vorhanden ist
        /// </summary>
        /// <param name="speicherpfad">Der Pfad in dem der Dateiname generiert werden soll</param>
        /// <returns>Gibt einen <see cref="string"/> zurück der den Namen einer Datei in dem angebenen Pfad enthält</returns>
        private string GetFileName(string speicherpfad)
        {
#if DEBUG
            return Path.Combine(speicherpfad, "BRIEF_1.pdf");
#endif
            string filename = $"BRIEF.pdf";

            string filepath = Path.Combine(speicherpfad, filename);
            (bool success, string file, string message) fileNameResult = FileErweiterung.FindSuitableFileName(filepath);

            if (fileNameResult.success)
            {
                filepath = fileNameResult.file;
            }



            return filepath;
        }

        /// <summary>
        /// Erstellt einen Brief als PDF in einem Pfad mit den angegebene Daten
        /// </summary>
        /// <param name="speicherpfad">Der Pfad in dem die PDF erstellt werden soll</param>
        /// <returns>Gibt den Pfad zu der PDF Briefdatei zurück</returns>
        public override string Print(string speicherpfad)
        {
            string filepath = GetFileName(speicherpfad);

#if CREATE_PREVIEW_HTML
            File.WriteAllText(filepath + ".html", _template);
#endif

            byte[] byteArray = Encoding.UTF8.GetBytes(_template);
            using MemoryStream inputStream = new MemoryStream(byteArray);
            ConverterProperties converterProperties = new ConverterProperties()
                .SetBaseUri(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LAYOUT_PATH));


            if (File.Exists(filepath))
            {
                File.Delete(filepath);
            }

            HtmlConverter.ConvertToPdf(inputStream, new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None), converterProperties);

            return filepath;
        }

        public byte[] PrintToMemory()
        {
            byte[] byteArray = Encoding.UTF8.GetBytes(_template);

            using MemoryStream outputStream = new MemoryStream();
            using MemoryStream inputStream = new MemoryStream(byteArray);
            ConverterProperties converterProperties = new ConverterProperties()
                .SetBaseUri(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LAYOUT_PATH));

            HtmlConverter.ConvertToPdf(inputStream, outputStream, converterProperties);

            return outputStream.ToArray();
        }

        /// <summary>
        /// Generiert die CSS Variablen die den Regeln nach Bereiche ein oder ausblenden
        /// </summary>
        /// <returns>Gibt eine CSS zurück die die Regeln der CSS enthält</returns>
        protected override string GenerateDisplayCss()
        {
            StringBuilder cssBuilder = new StringBuilder();
            cssBuilder.AppendLine("<style>");


            if (!_regeln.ShowFooter)
            {
                cssBuilder.AppendLine("\t#footer {");
                //cssBuilder.AppendLine("\t\tdisplay: none;");
                cssBuilder.AppendLine("\t\tvisibility: hidden;");
                cssBuilder.AppendLine("\t\topacity: 0;");
                cssBuilder.AppendLine("\t\tcolor: rgba(0,0,0,0);");
                cssBuilder.AppendLine("\t\ttransform: scale(0);");
                cssBuilder.AppendLine("\t}");
            }

            if (!_regeln.ShowHeader)
            {
                cssBuilder.AppendLine("\t.karley-header {");
                //cssBuilder.AppendLine("\t\tdisplay: none;");
                cssBuilder.AppendLine("\t\tvisibility: hidden;");
                cssBuilder.AppendLine("\t\topacity: 0;");
                cssBuilder.AppendLine("\t\tcolor: rgba(0,0,0,0);");
                cssBuilder.AppendLine("\t\ttransform: scale(0);");
                cssBuilder.AppendLine("\t}");
            }

            if (!_regeln.ShowAdresszeileLand)
            {
                cssBuilder.AppendLine("\t.display-empfaenger-land {");
                cssBuilder.AppendLine("\t\tdisplay: none;");
                cssBuilder.AppendLine("\t}");
            }

            if (!_regeln.ShowAdresszeile2)
            {
                cssBuilder.AppendLine("\t.display-addresszeile2 {");
                cssBuilder.AppendLine("\t\tdisplay: none;");
                cssBuilder.AppendLine("\t}");
            }

            if (!_regeln.ShowAdresszeile3)
            {
                cssBuilder.AppendLine("\t.display-addresszeile3 {");
                cssBuilder.AppendLine("\t\tdisplay: none;");
                cssBuilder.AppendLine("\t}");
            }

            if (!_regeln.ShowAdresszeile4)
            {
                cssBuilder.AppendLine("\t.display-addresszeile4 {");
                cssBuilder.AppendLine("\t\tdisplay: none;");
                cssBuilder.AppendLine("\t}");
            }

            cssBuilder.AppendLine("</style>");

            return cssBuilder.ToString();
        }

        /// <summary>
        /// Initialisiert die Werte des Objekt und rendert dabei das Template
        /// </summary>
        /// <returns></returns>
        protected override async Task InitializeAsync()
        {
            string layoutPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LAYOUT_PATH, _layoutFile);
            _template = await File.ReadAllTextAsync(layoutPath);
            SetRegeln();
            _template = await SetTemplateVariables();
        }

        protected override Task InitializeAsync(FbController2 fbController)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Setzt die Regeln der Klasse die für die CSS Generierung genutzt wird
        /// </summary>
        protected override void SetRegeln()
        {
            _regeln.ShowAdresszeileLand = _view.Empfänger.Land is not null && !_view.Empfänger.Land.LAND_A_ID.Equals("DE", StringComparison.OrdinalIgnoreCase);
            _regeln.ShowAdresszeile2 = !String.IsNullOrWhiteSpace(_view.Empfänger.Firma2);
            _regeln.ShowAdresszeile3 = !String.IsNullOrWhiteSpace(_view.Empfänger.Vorname) || !String.IsNullOrWhiteSpace(_view.Empfänger.Name);
            _regeln.ShowAdresszeile4 = false;
        }

        /// <summary>
        /// Generiert sich den Briefkopf String
        /// </summary>
        /// <returns>Gibt den Briefkopf zurück</returns>
        private string GetBriefkopf()
        {
            List<string> fields = new List<string>
            {
                GlobalConfig.Configuration.FirmenDaten.Firmenname,
                GlobalConfig.Configuration.FirmenDaten.Firmenanschrift.Strasse,
                $"{GlobalConfig.Configuration.FirmenDaten.Firmenanschrift.Postleitzahl} {GlobalConfig.Configuration.FirmenDaten.Firmenanschrift.Ort}"
            };
            return String.Join(" - ", fields);
        }





        /// <summary>
        /// Setzt grundlegende Template Variablen und ruft die anderen Template Funktionen auf
        /// </summary>
        /// <returns>Gibt einen <see cref="string"/> zurück der das gerenderte Template enhtält</returns>
        protected override async Task<string> SetTemplateVariables()
        {
            for (int i = 0; i < _view.PostVermerk.Length; i++)
            {
                _template = _template.Replace("{{ POST_VERMERK_" + (i + 1) + " }}", _view.PostVermerk[i]);
            }



            _template = _template
                .Replace("{{ IMPRESSUM }}", GlobalConfig.Configuration.FirmenDaten.ImpressumHtmlDruckformulare())
                .Replace("{{ ABS_FIRMA }}", GlobalConfig.Configuration.FirmenDaten.Firmenname)
                .Replace("{{ ABS_STRASSE }}", GlobalConfig.Configuration.FirmenDaten.Firmenanschrift.Strasse)
                .Replace("{{ ABS_LAND }}", GlobalConfig.Configuration.FirmenDaten.Firmenanschrift.Land)
                .Replace("{{ ABS_PLZ }}", GlobalConfig.Configuration.FirmenDaten.Firmenanschrift.Postleitzahl)
                .Replace("{{ ABS_ORT }}", GlobalConfig.Configuration.FirmenDaten.Firmenanschrift.Ort)
                .Replace("{{ ADDRESSZEILE1 }}", _view.Empfänger.Firma)
                .Replace("{{ ADDRESSZEILE2 }}", _view.Empfänger.Firma2)
                .Replace("{{ ADDRESSZEILE3 }}", $"{_view.Empfänger.Vorname} {_view.Empfänger.Name}".Trim())
                .Replace("{{ ADDRESSZEILE4 }}", String.Empty)
                .Replace("{{ EMP_STRASSE }}", _view.Empfänger.Strasse)
                .Replace("{{ EMP_PLZ }}", _view.Empfänger.Postleitzahl)
                .Replace("{{ EMP_ORT }}", _view.Empfänger.Ort)
                .Replace("{{ EMP_LAND }}", _view.Empfänger.Land.LAND_A_NAME)
                .Replace("{{ DISPLAY_CSS }}", GenerateDisplayCss())
                .Replace("{{ BRIEFKOPF }}", GetBriefkopf())
                .Replace("{{ BETREFF }}", _view.Betreff)
                .Replace("{{ INHALT }}", _view.Inhalt.Replace("\n", "<br/>").Replace("\r", ""))
                .Replace("{{ DATUM }}", DateTime.Now.ToString("dd.MM.yyyy"))
                ;

            return await Task.FromResult(_template);
        }




    }
}
