using System.Globalization;
using System.Net.Mime;
using QuestPDF.Drawing;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using Server.Data;

namespace Server.Model
{
    public class InvoiceDocument(InvoiceModel model) : IDocument
    {
        private InvoiceModel Model { get; } = model;

        public void Compose(IDocumentContainer container)
        {
            if(File.Exists("NotoSans-VariableFont_wdth,wght.ttf"))
                FontManager.RegisterFont(File.OpenRead("NotoSans-VariableFont_wdth,wght.ttf"));
            
            container.Page(page =>
            {
                page.Size(PageSizes.A4);
                page.Margin(10, Unit.Millimetre);
                page.MarginLeft(20, Unit.Millimetre);
                page.PageColor(Colors.White);
                page.DefaultTextStyle(x => x
                    .FontSize(10)
                    .FontFamily("NotoSans")
                    .Light());

                page.Header().Element(ComposeHeader);
                page.Content().Element(ComposeContent);
                page.Footer().Element(ComposeFooter);
                
            });
        }

        private void ComposeContent(IContainer container)
        {
            container.PaddingVertical(40).Column(outerColumn =>
            {
                outerColumn.Item().Element(ComposeItemTable);
                
                outerColumn.Item().Row(row =>
                {
                    row.RelativeItem().PaddingRight(10).Column(col =>
                    {
                        if (!string.IsNullOrWhiteSpace(Model.Comment))
                            col.Item().PaddingTop(25).Element(ComposeComments);
                    });
                    
                    row.AutoItem().Column(col =>
                    {
                        col.Item().Element(ComposeTaxTable);
                    });
                });
                
                outerColumn.Spacing(5);
            });
        }

        private void ComposeTaxTable(IContainer container)
        {
            container.PaddingTop(25).Table(table =>
            {
                table.ColumnsDefinition(c =>
                {
                    c.ConstantColumn(70);
                    c.ConstantColumn(25);
                    c.ConstantColumn(70);
                    c.ConstantColumn(45);
                });
                
                table.Header(header =>
                {
                    header.Cell();
                    header.Cell().AlignRight().TextSmall("", true);
                    header.Cell().AlignRight().TextSmall("Zwischensumme", true);
                    header.Cell().AlignRight().TextSmall("", true);
                    
                    header.Cell().Element(c => c.BorderBottom(1).BorderColor(Colors.Black));
                    header.Cell().Element(c => c.BorderBottom(1).BorderColor(Colors.Black)).AlignRight().TextSmall("USt. %", true);
                    header.Cell().Element(c => c.BorderBottom(1).BorderColor(Colors.Black)).AlignRight().TextSmall("(ohne USt.)", true);
                    header.Cell().Element(c => c.BorderBottom(1).BorderColor(Colors.Black)).AlignRight().TextSmall("USt.", true);
                });

                var totalTax = 0d;
                
                // 7%
                var tax7Items = Model.Items?.Where(x => x.TaxType == TaxType.Tax7).ToList() ?? [];
                if (tax7Items.Count > 0)
                {
                    var tax7Netto = tax7Items.Sum(x => x.PriceNetto * x.Quantity);
                    var tax7Tax = tax7Netto * 0.07;
                    totalTax += tax7Tax;

                    table.Cell();
                    table.Cell().AlignRight().TextSmall("7%");
                    table.Cell().AlignRight().TextSmall($"{tax7Netto:N2} €");
                    table.Cell().AlignRight().TextSmall($"{tax7Tax:N2} €");
                }
                
                // 19%
                var tax19Items = Model.Items?.Where(x => x.TaxType == TaxType.Tax19).ToList() ?? [];
                if (tax19Items.Count > 0)
                {
                    var tax19Netto = tax19Items.Sum(x => x.PriceNetto * x.Quantity);
                    var tax19Tax = tax19Netto * 0.19;
                    totalTax += tax19Tax;
                    
                    table.Cell();
                    table.Cell().AlignRight().TextSmall("19%");
                    table.Cell().AlignRight().TextSmall($"{tax19Netto:N2} €");
                    table.Cell().AlignRight().TextSmall($"{tax19Tax:N2} €");
                }
                
                // SUMME
                table.Cell().Element(c => c.BorderTop(1).BorderColor(Colors.Black)).TextSmall("USt. Gesamt");
                table.Cell().Element(c => c.BorderTop(1).BorderColor(Colors.Black));
                table.Cell().Element(c => c.BorderTop(1).BorderColor(Colors.Black)).AlignRight().TextSmall($"{Model.Items?.Sum(x => x.PriceNetto * x.Quantity):N2} €");
                table.Cell().Element(c => c.BorderTop(1).BorderColor(Colors.Black)).AlignRight().TextSmall($"{totalTax:N2} €");
            });
        }
        
        private void ComposeItemTable(IContainer container)
        {
            container.Table(table =>
            {
                // Define columns
                table.ColumnsDefinition(columns =>
                {
                    columns.RelativeColumn(3);
                    columns.ConstantColumn(20, Unit.Millimetre);
                    
                    columns.ConstantColumn(24, Unit.Millimetre);
                    columns.ConstantColumn(15, Unit.Millimetre);
                    columns.ConstantColumn(24, Unit.Millimetre);
                    columns.ConstantColumn(24, Unit.Millimetre);
                });
            
                // Describe header
                table.Header(header =>
                {
                    
                    header.Cell().Text("").SemiBold();
                    header.Cell().Text("").SemiBold();
                    header.Cell().AlignRight().Text("Einzelpreis").SemiBold();
                    header.Cell().Text("").SemiBold();
                    header.Cell().AlignRight().Text("Einzelpreis").SemiBold();
                    header.Cell().AlignRight().Text("Gesamtpreis").SemiBold();
                    
                    
                    header.Cell().Element(CellStyle).Text("Beschreibung").SemiBold();
                    header.Cell().Element(CellStyle).AlignCenter().Text("Menge").SemiBold();
                    header.Cell().Element(CellStyle).AlignRight().Text("(ohne USt.)").SemiBold();
                    header.Cell().Element(CellStyle).AlignRight().Text("USt. %").SemiBold();
                    header.Cell().Element(CellStyle).AlignRight().Text("(inkl USt.)").SemiBold();
                    header.Cell().Element(CellStyle).AlignRight().Text("(inkl USt.)").SemiBold();
                    
                    static IContainer CellStyle(IContainer container)
                    {
                        return container.DefaultTextStyle(x => x.SemiBold()).BorderBottom(1).BorderColor(Colors.Black);
                    }
                });
            
                // Describe content
                foreach (var item in Model.Items ?? [])
                {
                    
                    // Beschreibung
                    table.Cell().Element(CellStyle).Column(column =>
                    {
                        column.Item().Text(item.Name);
                        if(!string.IsNullOrWhiteSpace(item.Description)) 
                            column.Item().TextSmall(item.Description);
                    });
                    
                    table.Cell().Element(CellStyle).AlignCenter().Text(txt => txt.Span($"{item.Quantity:N2}"));

                    // string as currency format
                    table.Cell().Element(CellStyle).AlignRight().Text($"{item.PriceNetto:N2} €");
                    table.Cell().Element(CellStyle).AlignRight().Text($"{(int)item.TaxType}%");
                    table.Cell().Element(CellStyle).AlignRight().Text($"{item.PriceBrutto:N2} €");
                    table.Cell().Element(CellStyle).AlignRight().Text($"{item.PriceBrutto * item.Quantity:N2} €");
                    continue;

                    
                }
                
                table.Cell().ColumnSpan(5).Element(CellStyle).PaddingTop(10).Text("Rechnungsbetrag").Medium();
                table.Cell().Element(CellStyle).PaddingTop(10).AlignRight().Text($"{Model.Items.Sum(x=> x.PriceBrutto*x.Quantity):N2} €").Medium();
                
                return;

                static IContainer CellStyle(IContainer container) => container.BorderBottom(1).BorderColor(Colors.Grey.Lighten2).PaddingVertical(5);
            });
        }

        private void ComposeComments(IContainer container)
        {
            container.Background(Colors.Grey.Lighten3).Padding(10).Column(column =>
            {
                column.Spacing(5);
                column.Item().Text(Model.Comment);
            });
        }

        private void ComposeFooter(IContainer container)
        {
            container.Column(outerColumn =>
            {
                outerColumn.Item().Row(row =>
                {
                    row.RelativeItem().Column(column =>
                    {
                        column.Item().TextSmall(Model.Seller?.Name, true);
                        column.Item().TextSmall(Model.Seller?.Street);
                        column.Item().TextSmall($"{Model.Seller?.Zip} {Model.Seller?.City}");
                    });
                
                    row.RelativeItem().Column(column =>
                    {
                        if(!string.IsNullOrWhiteSpace(Model.Seller?.Phone)) column.Item().TextSmall($"Tel.: {Model.Seller?.Phone}");
                        if(!string.IsNullOrWhiteSpace(Model.Seller?.Email)) column.Item().TextSmall($"E-Mail: {Model.Seller?.Email}");
                        if(!string.IsNullOrWhiteSpace(Model.Seller?.Web)) column.Item().TextSmall($"Web: {Model.Seller?.Web}");
                    });
                
                    row.RelativeItem().Column(column =>
                    {
                        if(!string.IsNullOrWhiteSpace(Model.PaymentData?.BankName)) column.Item().TextSmall(Model.PaymentData?.BankName);
                        if(!string.IsNullOrWhiteSpace(Model.PaymentData?.Iban)) column.Item().TextSmall($"IBAN: {Model.PaymentData?.Iban}");
                        if(!string.IsNullOrWhiteSpace(Model.PaymentData?.Bic)) column.Item().TextSmall($"BIC: {Model.PaymentData?.Bic}");
                    });
                });
                
                outerColumn.Item().PaddingTop(3, Unit.Millimetre).AlignCenter().Text(txt =>
                {
                    txt.CurrentPageNumber();
                    txt.Span(" / ");
                    txt.TotalPages();
                });
            });
        }

        private void ComposeHeader(IContainer container)
        {
            container.Column(outerColumn =>
            {
                outerColumn.Item().Row(row =>
                {
                    row.RelativeItem().Column(col =>
                    {

                        if (!string.IsNullOrWhiteSpace(SettingsData.Instance.Logo) && File.Exists(SettingsData.Instance.Logo))
                            col.Item().Height(25, Unit.Millimetre).Image(SettingsData.Instance.Logo);
                        else
                            col.Item().Height(25, Unit.Millimetre);

                    });
                    
                    row.RelativeItem().AlignMiddle().PaddingRight(10, Unit.Millimetre).Background(Colors.Red.Medium).Column(col =>
                    {
                        col.Item().AlignRight().Text("www.example.com");
                    });
                });
                
                outerColumn.Item().PaddingTop(15, Unit.Millimetre).Row(row =>
                {
                    row.AutoItem().Column(column =>
                    {
                        column.Item().PaddingBottom(5).TextSmall(Model.Seller?.ToString(), true);
                        if(!string.IsNullOrWhiteSpace(Model.Customer?.Name)) column.Item().Text(Model.Customer?.Name);
                        if(!string.IsNullOrWhiteSpace(Model.Customer?.Name2)) column.Item().Text(Model.Customer?.Name2);
                        column.Item().Text(Model.Customer?.Street);
                        column.Item().Text($"{Model.Customer?.Zip} {Model.Customer?.City}");
                    });

                    row.RelativeItem();
                    
                    row.AutoItem().Column(col =>
                    {
                        col.Item().Table(table =>
                        {
                            table.ColumnsDefinition(c =>
                            {
                                c.ConstantColumn(50);
                                c.ConstantColumn(50);
                            });
                        
                            table.Cell().TextSmall("Steuer-Nr:", true);
                            table.Cell().TextSmall(Model.Seller?.TaxId);
                            
                            table.Cell().TextSmall("Datum:", true);
                            table.Cell().TextSmall(Model.IssueDate.ToShortDateString());
                            
                            table.Cell().TextSmall("Rechnung:", true);
                            table.Cell().TextSmall($"#{Model.InvoiceId}");
                        });
                    });
                });
            });
        }
    }
}