using KarleyLibrary.Erweiterungen;
using Microsoft.AspNetCore.Components;
using s2industries.ZUGFeRD;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Toolbelt.Blazor.HotKeys;
using WK5.Core;
using WK5.Core.Basis;
using WK5.Core.Basis.Erweiterungen;
using WK5.Core.Basis.Filter;
using WK5.Core.Drucken.Rechnungen;
using WK5.Core.Email;
using WK5.Core.Models;
using WK5.Core.PageModels.Verkauf.Rechnungen;
using WK5.Core.Services;

namespace WK5_Blazor.Pages.Verkauf.Rechnungen
{
    public partial class RechnungsForm
    {
        [Parameter] public int Rechnungsnummer { get; set; }

        private bool _showKundenArtikelhistorieModal;
        private bool _showÜbernahmeModal;
        public bool _showSeriennummerModal;
        public bool _xRechnungLädt;
        public RechnungsForm()
        {
            Input = new Rechnung();
            FilterPakete.Typ = PaketTyp.Rechnung;
            FilterZeiterfassung.Option = ZeitenFilterOption.Rechnung;
            ActiveTab = RechnungTabs.Kundendaten;
            StartCopy = new Rechnung();
            EditOnlyTabs.Add(RechnungTabs.Dokumentenablage);
            EditOnlyTabs.Add(RechnungTabs.Historie);
        }
        public override string ActivePageName => Modus switch
        {
            EditMode.Anlage => "Neue Rechnung",
            EditMode.Bearbeiten => $"RE-{Rechnungsnummer}",
            _ => "Unbekannt"
        };
        public override string FinalBreadcrumbItemName => Modus switch
        {
            EditMode.Anlage => "Neu",
            EditMode.Bearbeiten => $"{Rechnungsnummer}",
            _ => "Unbekannt"
        };
        protected override async Task OnParametersSetAsync()
        {
            _versandMehrwertsteuer = await Mehrwertsteuer.GetVersandMehrwertsteuerAsync();

            if (Rechnungsnummer > 0)
            {
                await LadeEditModeAsync();
            }

            FilterPakete.Nummer = Rechnungsnummer.ToString();
            FilterZeiterfassung.Suchbegriff = Rechnungsnummer.ToString();
            FilterZeiterfassung.Kundennummer = Input.Kundennummer;


            if (Kunde is null)
            {
                _showKundenSucheModal = true;
            }



            StartCopy = Input.DeepCopy();
            await SetAlerts();
        }
        public async override Task LadeEditModeAsync()
        {
            using FbController2 fbController = new FbController2();
            Rechnung? rechnung = await Rechnung.GetRechnungAsync(Rechnungsnummer, fbController);
            if (rechnung is not null)
            {
                Kunde = await Kunde.GetKundeAsync(rechnung.Kundennummer);
                if (Kunde is not null)
                {
                    await KundeSelectedAsync(Kunde);
                    Input = rechnung;
                    _zähler = rechnung.Positionen.Count;
                    Gesperrt = rechnung.BELE_L_UBERNAHME || rechnung.GutschriftnummerVerknüpfung > 0 || Input.BELE_L_FIBUUEBERGABE;
                    await LieferanschriftChangedAsync(Input.LieferanschriftId);
                    await RechnungsanschriftChangedAsync(Input.RechnungsanschriftId);
                    await PositionSelected(Input.Positionen.FirstOrDefault());
                    await LieferbedingungSelectedAsync(Input.LieferbedingungId);
                    _subBelege = await belegService.GetSubBelege(BelegTyp.Rechnung, Rechnungsnummer, fbController);
                    Modus = EditMode.Bearbeiten;
                }
            }
            else
            {
                await AddAlertAsync(new AlertBox
                {
                    AlertType = AlertType.Danger,
                    Message = $"Rechnung {Rechnungsnummer} konnte nicht gefunden werden."
                });


                navigationManager.NavigateTo("/Rechnungen");
            }

            if (!_isDisposed)
            {
                await CheckActivePageAsync();
            }
        }
        private async Task SubmitAsync()
        {
            if ((NurDurchAdminZuBearbeiten && !Mitarbeiter.IsAdmin) || SperreDurchAnderenUser || !Input.HasBeenModified(StartCopy))
            {
                return;
            }


            if (_editForm is null || _editForm.EditContext is null || Kunde is null)
            {
                return;
            }

            if (_editForm.EditContext.Validate())
            {
                using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
                await fbController.StartTransactionAsync();
                try
                {
                    if (Modus is EditMode.Anlage)
                    {
                        await belegService.CreateAsync(Input, Kunde, Program.AppDaten.Optionen, fbController);
                        await AddAlertAsync(new AlertBox
                        {
                            AlertType = AlertType.Success,
                            Message = $"Rechnung {Input.Belegnummer} erfolgreich angelegt",
                            DecayTime = 10
                        });
                    }
                    else
                    {
                        if (Input.BELE_L_FIBUUEBERGABE || Input.BELE_L_ERLEDIGT || (Gesperrt && !Mitarbeiter.IsAdmin))
                        {

                            await belegService.UpdateGesperrtenBelegAsync(Input, fbController);
                            await AddAlertAsync(new AlertBox
                            {
                                AlertType = AlertType.Success,
                                Message = $"Notiz und Einkaufspreise wurden erfolgreich gespeichert",
                                DecayTime = 10
                            });
                        }
                        else if ((!Gesperrt || (Gesperrt && Mitarbeiter.IsAdmin)) && !Input.BELE_L_FIBUUEBERGABE && !Input.BELE_L_ERLEDIGT)
                        {
                            await belegService.UpdateAsync(Input, Kunde, Program.AppDaten.Optionen, fbController);

                            await AddAlertAsync(new AlertBox
                            {
                                AlertType = AlertType.Success,
                                Message = $"Rechnung {Input.Belegnummer} erfolgreich gespeichert",
                                DecayTime = 10
                            });
                        }

                    }
                    await fbController.CommitChangesAsync();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    await fbController.RollbackChangesAsync();
                    throw;
                }

                if (Modus is EditMode.Anlage)
                {
                    navigationManager.NavigateTo($"/Rechnungen/{Input.Belegnummer}");
                }
                else
                {
                    await OnParametersSetAsync();
                }


            }


        }
        private async Task ÜbernahmeAsync()
        {

            using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
            await fbController.StartTransactionAsync();
            try
            {
                Rechnung? rechnung = await Rechnung.GetRechnungAsync(Rechnungsnummer, fbController);

                if (rechnung is not null && Kunde is not null)
                {
                    Gutschrift neueGutschrift = (Gutschrift)await belegService.ÜbernahmeAsync(rechnung, Kunde, Program.AppDaten.Optionen, Program.AppDaten.VersandMehrwertsteuer, fbController, Mitarbeiter.PersonalNummer);

                    await AddAlertAsync(new AlertBox
                    {
                        AlertType = AlertType.Success,
                        Message = $"RE-{Rechnungsnummer} wurde erfolgreich in GU-{neueGutschrift.Belegnummer} übernommen",
                        DecayTime = 10
                    });

                    await fbController.CommitChangesAsync();
                    navigationManager.NavigateTo($"/Gutschriften/{neueGutschrift.Belegnummer}");


                }
            }
            catch (Exception)
            {
                await fbController.RollbackChangesAsync();
                throw;
            }



        }
        private async Task KopierenAsync()
        {
            if (Modus is EditMode.Bearbeiten)
            {
                using FbController2 fbController = new FbController2(Mitarbeiter.PersonalNummer);
                await fbController.StartTransactionAsync();
                try
                {

                    Rechnung? rechnung = await Rechnung.GetRechnungAsync(Rechnungsnummer, fbController);
                    if (rechnung is null)
                    {
                        throw new ArgumentNullException(nameof(rechnung));
                    }

                    if (Kunde is null)
                    {
                        throw new ArgumentNullException(nameof(Kunde));
                    }

                    var (NeuerBeleg, Messages) = await belegService.CopyAsync(rechnung, Kunde, Program.AppDaten.Optionen, fbController, Mitarbeiter.PersonalNummer);
                    await AddAlertsAsync(Messages);
                    if (NeuerBeleg is not null)
                    {
                        await fbController.CommitChangesAsync();
                        await AddAlertAsync(new AlertBox
                        {
                            AlertType = AlertType.Success,
                            Message = "Rechnung wurde erfolgreich kopiert.",
                            DecayTime = 10
                        });

                        navigationManager.NavigateTo($"/Rechnungen/{NeuerBeleg.Belegnummer}");
                    }
                }
                catch (Exception)
                {
                    await fbController.RollbackChangesAsync();
                    throw;
                }
            }
        }
        public async override Task DownloadAsync(bool confirmed = false)
        {
            if (Kunde is null)
            {
                return;
            }

            _isDownloading = true;
            StateHasChanged(); // Wird für den Shortcut benötigt
            using FbController2 fbController = new FbController2();
            var rechnung = await Rechnung.GetRechnungAsync(Rechnungsnummer, fbController);

            if (rechnung is not null)
            {

                PrintRechnungRegelsatz printRegeln = new PrintRechnungRegelsatz
                {
                    ShowFooter = true,
                    ShowHeader = true,
                    IsHybridMail = Kunde.KUND_WK5_L_REDRUCK
                };

                if (Program.AppDaten.VersandMehrwertsteuer is null)
                {
                    throw new ArgumentNullException(nameof(Program.AppDaten.VersandMehrwertsteuer));
                }


                PrintRechnung printer = await PrintRechnung.CreateAsync(rechnung, printRegeln, fbController);
                string filenamePdf = printer.Print(GlobalConfig.Configuration.OutputPfad);
                await belegService.SetDruckdatumAsync(BelegTyp.Rechnung, Rechnungsnummer, fbController);

                await downloadService.DownloadFile($"RE-{Rechnungsnummer}.pdf", await File.ReadAllBytesAsync(filenamePdf), "application/pdf");
                await downloadService.ClearBuffers();
            }

            _isDownloading = false;
        }
        public async override Task ÖffneMailAsync(bool confirmed = false)
        {

            if (Kunde is null)
            {
                return;
            }

            if (Kunde.KUND_A_EMAIL is null)
            {
                await jsRuntime.ShowToast(ToastType.error, "Rechnung konnte nicht in David geöffnet werden, da beim Kunden keine Mailadresse hinterlegt ist");
                return;
            }

            _mailIsLoading = true;
            StateHasChanged(); // Wird für den Shortcut benötigt
            using FbController2 fbController = new FbController2();
            var rechnung = await Rechnung.GetRechnungAsync(Rechnungsnummer, fbController);

            if (rechnung is not null)
            {

                string empfängerEmail = Kunde.KUND_A_EMAIL;

                Ansprechpartner? ansprechpartner = await Ansprechpartner.GetAnsprechpartnerByNameAsync(rechnung.Kundennummer, rechnung.Ansprechpartner);
                if (ansprechpartner is not null && !String.IsNullOrWhiteSpace(ansprechpartner.PART_A_EMAIL))
                {
                    empfängerEmail = ansprechpartner.PART_A_EMAIL;
                }

                if (rechnung.RechnungsanschriftId > 0)
                {
                    Rechnungsanschrift? rechnungsanschrift = await Rechnungsanschrift.GetRechnungsanschriftAsync(rechnung.Kundennummer, rechnung.RechnungsanschriftId);

                    if (rechnungsanschrift is not null && !String.IsNullOrWhiteSpace(rechnungsanschrift.KURE_A_EMAIL))
                    {
                        empfängerEmail = rechnungsanschrift.KURE_A_EMAIL;
                    }
                }

                if (String.IsNullOrWhiteSpace(empfängerEmail))
                {
                    await jsRuntime.ShowToast(ToastType.error, "Auftrag konnte nicht in David geöffnet werden, da beim Kunden keine Mailadresse hinterlegt ist");
                    return;
                }


                KarleyBrowserInterfaceEmail email = new KarleyBrowserInterfaceEmail
                {
                    Absender = GlobalConfig.EmailInfoEU,
                    Empfänger = empfängerEmail,
                    Content = String.Empty,
                    Betreff = $"Rechnung {Rechnungsnummer}"
                };

                PrintRechnungRegelsatz printRegeln = new PrintRechnungRegelsatz
                {
                    ShowFooter = true,
                    ShowHeader = true,
                    IsHybridMail = true
                };

                if (Program.AppDaten.VersandMehrwertsteuer is null)
                {
                    throw new ArgumentNullException(nameof(Program.AppDaten.VersandMehrwertsteuer));
                }

                PrintRechnung printer = await PrintRechnung.CreateAsync(rechnung, printRegeln, fbController);
                string filenamePdf = printer.Print(GlobalConfig.Configuration.OutputPfad);
                await belegService.SetDruckdatumAsync(BelegTyp.Auftrag, Rechnungsnummer, fbController);
                email.Anhänge.Add(filenamePdf);

                var (success, data, _) = KarleyLibrary.Serialization.XMLWriter.Serialize(email);
                if (success)
                {
                    string xmlFilename = $"{email.GetHashCode()}.xml";
                    await File.WriteAllTextAsync(Path.Combine(GlobalConfig.Configuration.OutputPfad, xmlFilename), data);
                    await jsRuntime.OpenNewTab($"karley:davidMail;{xmlFilename}");
                }


            }
            _mailIsLoading = false;

        }

        public override async Task CheckActivePageAsync()
        {
            var (success, page) = ActivePages.AddActivePage(new ActivePage(PageType.Rechnung, Rechnungsnummer.ToString(), Mitarbeiter.PersonalNummer));

            if (success)
            {
                Page = page;
            }
            else
            {
                await AddAlertAsync(new AlertBox
                {
                    AlertType = AlertType.Danger,
                    Message = $"Die Rechnung wird zurzeit durch {Program.AppDaten.GetMitarbeiterName(page.UserId)} bearbeitet."
                });

                SperreDurchAnderenUser = true;
            }
        }

        public async Task OnTabChange(RechnungTabs newActiveTab)
        {
            switch (newActiveTab)
            {
                case RechnungTabs.Positionen:
                    if (Input.Positionen.Count is 0)
                    {
                        _showArtikelSucheModal = true;
                    }
                    break;
                case RechnungTabs.Historie:
                    await LadeHistorieAsync();
                    break;
                default:
                    break;
            }
        }

        public override void AddHotKeys(HotKeysContext context)
        {
            context.Add(ModKeys.Alt, Keys.S, SubmitAsync, "Speichert den Auftrag", Exclude.Default);
            base.AddHotKeys(context);
        }

        public bool _showXRechnungModal = false;
        public AlertBox? xRechnungAlert { get; set; } = null;

        public XRechnungInput xRechnungInput { get; set; } = new XRechnungInput();

        public async Task GetXRechnung()
        {
            xRechnungAlert = null;
            _xRechnungLädt = true;
            StateHasChanged();

            Kunde? kunde = await Kunde.GetKundeAsync(Input.Kundennummer);
            if (kunde is not null)
            {
                if (!String.IsNullOrWhiteSpace(kunde.KUND_WK5_A_LEITWEG_ID))
                {
                    XRechnungService xrechnung = new XRechnungService();
                    using MemoryStream stream = new MemoryStream();

                    try
                    {
                        InvoiceDescriptor desc = await xrechnung.ToXRechnung(Input);
                        //desc.Save(stream, ZUGFeRDVersion.Version21, Profile.XRechnung);                        

                        //string xml = System.Text.Encoding.UTF8.GetString(stream.ToArray());

                        //if (xRechnungInput.ShowXRechnungVersion)
                        //{
                        //    string from = "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.1";
                        //    xml = xml.Replace(from, xRechnungInput.XRechnungVersionString);
                        //}

                        //if(xRechnungInput.Profile == Profile.XRechnung1)
                        //{
                        //    string from = "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.1";
                        //    xml = xml.Replace(from, XRechnungInput.Version120);
                        //}

                        string xml = xrechnung.ToPDF(desc, xRechnungInput.Version, xRechnungInput.Profile, xRechnungInput.ShowXRechnungVersion ? xRechnungInput.XRechnungVersion : null);

                        await downloadService.DownloadFileFromText($"{Input.Belegtyp}-{Input.Belegnummer}.xml", xml, Encoding.UTF8,"text/xml");                        
                    }
                    catch (Exception ex)
                    {
                        xRechnungAlert = new AlertBox(ex.Message, AlertType.Danger);
                    }
                }
                else
                {
                    xRechnungAlert = new AlertBox("Bei dem Kunden ist keine Leitweg-ID gesetzt!", AlertType.Danger);
                }
            }
            else
            {
                xRechnungAlert = new AlertBox("Der Kunde konnte nicht gefunden werden!", AlertType.Danger);
            }

            _xRechnungLädt = false;
        }
    }

    public class XRechnungInput
    {
        public ZUGFeRDVersion Version { get; set; } = ZUGFeRDVersion.Version21;
        public Profile Profile { get; set; } = Profile.XRechnung;
        public List<Profile> AvailableProfiles
        {
            get
            {
                List<Profile> profiles = new List<Profile>();
                switch (Version)
                {
                    case ZUGFeRDVersion.Version1:
                        profiles = new List<Profile> { Profile.Basic, Profile.Comfort, Profile.Extended };
                        break;
                    case ZUGFeRDVersion.Version20:
                        profiles = new List<Profile> { Profile.Minimum, Profile.Basic, Profile.BasicWL, Profile.Comfort, Profile.Extended };
                        break;
                    case ZUGFeRDVersion.Version21:
                        profiles = new List<Profile> { Profile.Minimum, Profile.Basic, Profile.BasicWL, Profile.Comfort, Profile.Extended, Profile.XRechnung1, Profile.XRechnung };
                        break;
                    default:
                        profiles = new List<Profile>();
                        break;
                }

                if (!profiles.Contains(Profile))
                {
                    Profile = profiles.First();
                }

                return profiles;
            }
        }

        public bool ShowXRechnungVersion => Profile == Profile.XRechnung;
        public XRechnungVersion XRechnungVersion { get; set; } = XRechnungVersion.Version211;
        public string XRechnungVersionString => XRechnungVersion switch
        {
            XRechnungVersion.Version200 => XRechnungDefinitions.Version200,
            XRechnungVersion.Version211 => XRechnungDefinitions.Version211,
            XRechnungVersion.Version220 => XRechnungDefinitions.Version220,
            _ => ""
        };

        
    }

    
}
