using KarleyLibrary.Attributes;
using KarleyLibrary.Erweiterungen;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using WK5.Core.Models;

namespace WK5.Core.OnlineShop.Models
{
    /// <summary>
    /// Stellt eine Onlinebestellung dar.
    /// <para>
    /// Die Daten werden durch den ShopImport angepasst und mithilfe der entsprechenden Methoden in passende W4 Objekte umgewandelt.
    /// <list type="table">
    /// <item>
    /// <see cref="ToW4VergleichsKunde"/>
    /// </item>
    /// <item>
    /// <see cref="ToW4Kunde(int)"/>
    /// </item>
    /// <item>
    /// <see cref="ToLieferanschrift(int)"/>
    /// </item>
    /// <item>
    /// <see cref="ToAnsprechpartner"/>
    /// </item>
    /// <item>
    /// <see cref="ToRechnungsanschrift(int)"/>
    /// </item>
    /// </list>
    /// </para>
    /// </summary>
    public class ShopOrder
    {
        private ShopLandCollection _shopLänder;

        public ShopOrder(ShopLandCollection landCollection)
        {
            _shopLänder = landCollection;
        }

        #region Felder

        private string _firstname = String.Empty;
        private string _lastname = String.Empty;

        private int _customer_id;
        private int _versandcode = 1;
        private string _paymentCode = String.Empty;

        private string _paymentCountry = String.Empty;
        private string? _shippingCountry;
        private string? _shippingCode;
        private string _comment = String.Empty;
        private string? _shippingAddress1;
        private string? _shippingAddress2;
        private string _paymentAddress1 = String.Empty;
        private string _paymentAddress2 = String.Empty;
        private string _customField = String.Empty;
        private string _paymentTaxId = String.Empty;
        private string _paymentFirstname = String.Empty;
        private string _paymentLastname = String.Empty;
        private string _paymentCompany = String.Empty;
        private string _shippingFirstname = String.Empty;
        private string _shippingLastname = String.Empty;
        private string _shippingCompany = String.Empty;

        #endregion
        #region Datenbankfelder
        [CompareField("order_id")]
        public int OrderId { get; set; }
        [CompareField("store_id")]
        public int StoreId { get; set; }
        [CompareField("store_name")]
        public string StoreName { get; set; } = "karley.de";
        [CompareField("store_url")]
        public string StoreUrl { get; set; } = "https://www.karley.de/";
        [CompareField("customer_id")]
        public int CustomerId
        {
            get => _customer_id;
            set
            {
                if (value == 0)
                {
                    WarGastbestellung = true;
                }

                _customer_id = value;
            }
        }
        [CompareField("customer_group_id")]
        public int CustomerGroupId { get; set; }

        public string Firstname
        {
            get => _firstname;
            set
            {
                _firstname = WebUtility.HtmlDecode(value);
            }
        }

        public string Lastname
        {
            get => _lastname;
            set
            {
                _lastname = WebUtility.HtmlDecode(value);
            }
        }

        public string Email { get; set; } = String.Empty;

        public string Telephone { get; set; } = String.Empty;

        public string Fax { get; set; } = String.Empty;

        [CompareField("custom_field")]
        public string CustomField
        {
            get => _customField;
            set
            {
                _customField = value;

                if (PaymentTaxId.Length == 0)
                {
                    try
                    {
                        dynamic json = Newtonsoft.Json.Linq.JObject.Parse(CustomField.Replace("\"5\"", "\"tax\""));
                        PaymentTaxId = json.tax.Value;
                    }
                    catch (Exception)
                    { }
                }
            }
        }

        #region Rechnungsanschrift
        [CompareField("payment_firstname")]
        public string PaymentFirstname
        {
            get => _paymentFirstname;
            set
            {
                if (value is null)
                {
                    return;
                }

                _paymentFirstname = WebUtility.HtmlDecode(value);
            }
        }
        [CompareField("payment_lastname")]
        public string PaymentLastname
        {
            get => _paymentLastname;
            set
            {
                if (value is null)
                {
                    return;
                }

                _paymentLastname = WebUtility.HtmlDecode(value);
            }
        }
        public string PaymentName => $"{PaymentFirstname} {PaymentLastname}";
        [CompareField("payment_company")]
        public string PaymentCompany
        {
            get => _paymentCompany;
            set
            {
                if (value is null)
                {
                    return;
                }

                _paymentCompany = WebUtility.HtmlDecode(value);
            }
        }
        [CompareField("payment_address_1")]
        public string PaymentAddress1
        {
            get => _paymentAddress1;
            set
            {
                if (value is null)
                {
                    return;
                }

                _paymentAddress1 = WebUtility.HtmlDecode(value);
            }
        }
        [CompareField("payment_address_2")]
        public string PaymentAddress2
        {
            get => _paymentAddress2;
            set
            {
                if (value is null)
                {
                    return;
                }

                _paymentAddress2 = WebUtility.HtmlDecode(value);
            }
        }
        [CompareField("payment_city")]
        public string PaymentCity { get; set; } = String.Empty;
        [CompareField("payment_postcode")]
        public string PaymentPostcode { get; set; } = String.Empty;
        [CompareField("payment_country")]
        public string PaymentCountry
        {
            get => _paymentCountry;
            set
            {
                if (value is null)
                {
                    return;
                }

                _paymentCountry = _shopLänder[value]?.IsoCode2 ?? "DE";
            }
        }
        [CompareField("payment_country_id")]
        public int PaymentCountryId { get; set; }
        [CompareField("payment_zone")]
        public string PaymentZone { get; set; } = String.Empty;
        [CompareField("payment_zone_id")]
        public int PaymentZoneId { get; set; }

        [CompareField("payment_address_format")]
        public string PaymentAddressFormat { get; set; } = String.Empty;

        [CompareField("payment_custom_field")]
        public string PaymentCustomField { get; set; } = String.Empty;
        [CompareField("payment_method")]
        public string PaymentMethod { get; set; } = String.Empty;
        [CompareField("payment_code")]
        public string PaymentCode
        {
            get => _paymentCode;
            set
            {
                _paymentCode = value;
                PaymentCodeId = Zahlungsart(value);
            }
        }

        #endregion
        #region Lieferanschrift
        [CompareField("shipping_firstname")]
        public string ShippingFirstname
        {
            get => _shippingFirstname;
            set
            {
                if (value is null)
                {
                    return;
                }

                _shippingFirstname = WebUtility.HtmlDecode(value);
            }
        }
        [CompareField("shipping_lastname")]
        public string ShippingLastname
        {
            get => _shippingLastname;
            set
            {
                if (value is null)
                {
                    return;
                }

                _shippingLastname = WebUtility.HtmlDecode(value);
            }
        }
        [CompareField("shipping_company")]
        public string ShippingCompany
        {
            get => _shippingCompany;
            set
            {
                if (value is null)
                {
                    return;
                }

                _shippingCompany = WebUtility.HtmlDecode(value);
            }
        }
        [CompareField("shipping_address_1")]
        public string? ShippingAddress1
        {
            get => _shippingAddress1;
            set
            {
                _shippingAddress1 = WebUtility.HtmlDecode(value);
            }
        }

        [CompareField("shipping_address_2")]
        public string? ShippingAddress2
        {
            get => _shippingAddress2;
            set
            {
                _shippingAddress2 = WebUtility.HtmlEncode(value);
            }
        }
        [CompareField("shipping_city")]
        public string? ShippingCity { get; set; } = String.Empty;
        [CompareField("shipping_postcode")]
        public string? ShippingPostcode { get; set; } = String.Empty;
        [CompareField("shipping_country")]
        public string? ShippingCountry
        {
            get => _shippingCountry;
            set
            {
                if (value is not null)
                {
                    _shippingCountry = _shopLänder[value]?.IsoCode2;
                }
            }
        }
        [CompareField("shipping_country_id")]
        public int ShippingCountryId { get; set; }
        [CompareField("shipping_zone")]
        public string? ShippingZone { get; set; } = String.Empty;
        [CompareField("shipping_zone_id")]
        public int ShippingZoneId { get; set; }

        [CompareField("shipping_address_format")]
        public string? ShippingAddressFormat { get; set; } = String.Empty;

        [CompareField("shipping_custom_field")]
        public string? ShippingCustomField { get; set; } = String.Empty;
        [CompareField("shipping_method")]
        public string? ShippingMethod { get; set; } = String.Empty;
        [CompareField("shipping_code")]
        public string? ShippingCode
        {
            get => _shippingCode;
            set
            {
                _shippingCode = value;
                // Wenn es keinen ShippingCode gibt, dann handelt es sich um eine Bestellung, welche keinen Versand erfordert -> Also Lieferbedingung Download
                if (_shippingCode is null)
                {
                    Versandcode = 7;
                }
                else if (_shippingCode.Contains("express", StringComparison.OrdinalIgnoreCase))
                {
                    Versandcode = 6;
                }
                else if (_shippingCode.Contains("pickup", StringComparison.OrdinalIgnoreCase))
                {
                    Versandcode = 10;
                }
                else
                {
                    Versandcode = 1; // Standard Versand
                }
            }
        }

        #endregion
        public string Comment
        {
            get => _comment;
            set
            {
                _comment = WebUtility.HtmlDecode(value);
            }
        }

        public decimal Total { get; set; }

        [CompareField("order_status_id")]
        public int OrderStatusId { get; set; }
        [CompareField("marketing_id")]
        public int MarketingId { get; set; }

        public string Tracking { get; set; } = String.Empty;
        [CompareField("language_id")]
        public int LanguageId { get; set; } = 2; // Mit Deutsch vorbelegt
        [CompareField("date_added")]
        public DateTime DateAdded { get; set; }
        [CompareField("date_modified")]
        public DateTime DateModified { get; set; }
        [CompareField("payment_tax_id")]
        public string PaymentTaxId
        {
            get => _paymentTaxId;
            set
            {
                if (value is null)
                {
                    value = String.Empty;
                }

                if (_paymentTaxId == String.Empty)
                {
                    _paymentTaxId = value;
                }
            }
        }
        [CompareField("authorization_id")]
        public string? TransaktionsId { get; set; }
        #endregion
        public string Anrede { get; set; } = "Sehr geehrte Damen und Herren,";

        private int Zahlungsart(string zahlartText)
        {
            int RetZahlungsart = 22;
            //Bar Kasse, = COD, wenn Shipping = pickup
            /*
            1	Bar Kasse neu:21
            2	Vorkasse  -- > bank_transfer neu:22
            3	Nachnahme -- > cod neu: 23
            4	Zahlung über Amazon bezahlt neu: 24
            11	Rechnung innerhalb 7 Tagen netto --> rechnung, KarleyRechnung
            12	Rechnung innerhalb 14 Tagen netto
            13	Rechnung 14 T 2% oder 30 Tage netto 
            14	Rechnung innerhalb 30 Tagen netto
            15	Rechnung 60 Tage oder 14Tage 2%
            16	Rechnung 120T netto 60Tage 3%
            17	Rechnung 14T 3% oder 21 Tage netto
            18	Rechnung innerhalb 60 Tagen netto
            19	Vorkasse 2% Skonto
            20	Lastschrifteinzug
            30	Paypal -- > pp_standard -- > pp_express
            31	Sofortüberweisung  -- > directebanking
            32	Billpay Factoring*/

            // Standard ist Vorkasse, also müssen wir das nicht abfragen!

            if (zahlartText.StartsWith("Nachnahme"))
            {
                RetZahlungsart = 23;
            }

            if (zahlartText.ToLower().Contains("nachnahme"))
            {
                RetZahlungsart = 23;
            }

            if (zahlartText.ToLower().Contains("cod"))
            {
                RetZahlungsart = 23;
            }

            if (zahlartText.ToLower().StartsWith("paypal"))
            {
                RetZahlungsart = 30;
            }

            if (zahlartText.ToLower().Contains("paypal"))
            {
                RetZahlungsart = 30;
            }

            if (zahlartText.ToLower().StartsWith("paypal_ipn"))
            {
                RetZahlungsart = 30;
            }

            if (zahlartText.ToLower().StartsWith("pp_express"))
            {
                RetZahlungsart = 30;
            }

            if (zahlartText.ToLower().StartsWith("pp_standard"))
            {
                RetZahlungsart = 30;
            }

            if (zahlartText.ToLower().StartsWith("directebanking"))
            {
                RetZahlungsart = 31;
            }

            if (zahlartText.ToLower().Contains("directebanking"))
            {
                RetZahlungsart = 31;
            }

            if (zahlartText.ToLower().StartsWith("ksofort"))
            {
                RetZahlungsart = 31;
            }

            if (zahlartText.ToLower().Contains("ksofort"))
            {
                RetZahlungsart = 31;
            }

            if (zahlartText.ToLower().StartsWith("billsafe"))
            {
                RetZahlungsart = 32;
            }

            if (zahlartText.ToLower().Contains("billsafe"))
            {
                RetZahlungsart = 32;
            }

            if (zahlartText.ToLower().StartsWith("KarleyRechnung"))
            {
                RetZahlungsart = 11;
            }

            if (zahlartText.ToLower().StartsWith("bill_me"))
            {
                RetZahlungsart = 11;
            }

            if (zahlartText.ToLower().Contains("rechnung"))
            {
                RetZahlungsart = 11;
            }

            if (zahlartText.ToLower().StartsWith("invoice"))
            {
                RetZahlungsart = 11;
            }

            if (zahlartText.ToLower().StartsWith("invoice"))
            {
                RetZahlungsart = 11;
            }

            if (zahlartText.StartsWith("Barzahlung"))
            {
                RetZahlungsart = 21;
            }

            if (zahlartText.ToLower().Contains("barzahlung"))
            {
                RetZahlungsart = 21;
            }

            if (zahlartText.ToLower().Contains("cop"))
            {
                RetZahlungsart = 21;
            }

            if (zahlartText.ToLower().StartsWith("cash"))
            {
                RetZahlungsart = 21;
            }

            if (zahlartText.ToLower().StartsWith("direct_debit"))
            {
                RetZahlungsart = 20;
            }

            if (zahlartText.ToLower().Contains("direct_debit"))
            {
                RetZahlungsart = 20;
            }

            return RetZahlungsart;
        }
        public int PaymentCodeId { get; set; } = 2; // Standard ist Vorkasse

        /// <summary>
        /// Ruft einen Wert ab, welcher die Versandart des Auftrags in der W4 angibt.
        /// </summary>
        public int Versandcode
        {
            get => _versandcode;
            set
            {
                if (value == 1 || value == 6 || Versandcode == 7 || value == 10)
                {
                    _versandcode = value;
                }
            }
        }
        /// <summary>
        /// Ruft einen Wert ab, der angibt, ob die Bestellung eine Gastbestellung gewesen ist
        /// </summary>
        public bool WarGastbestellung { get; protected set; } = false;


        /// <summary>
        /// Erstellt aus der ShopOrder ein W4 Kunden Objekt zum abgleichen der Daten mit alternativen Kunden.
        /// <para>
        /// Wird z.B. verwendet für
        /// <see cref="WK5.Core.Services.KundenService.GetÄhnlicheKundenAsync(Kunde)"/>
        /// </para>
        /// </summary>
        /// <returns></returns>
        public Kunde ToW4VergleichsKunde()
        {
            return new Kunde
            {
                KUND_A_NR = CustomerId.ToString(),
                KUND_A_NAME1 = PaymentFirstname,
                KUND_A_NAME2 = PaymentCompany ?? String.Empty,
                KUND_A_TEL1 = Telephone,
                KUND_A_TEL2 = Telephone,
                KUND_A_HANDY = Telephone,
                KUND_A_EMAIL = Email,
                KUND_A_FAX = Fax
            };
        }

        /// <summary>
        /// Erstellt aus der ShopOrder einen Kunden der in der W4 eingefügt werden kann.
        /// <para>
        /// Diese Methode sollte nur dann aufgerufen werden, wenn die Daten der ShopOrder sich nicht mehr verändern können.
        /// </para>
        /// </summary>
        /// <returns></returns>
        public Kunde ToW4Kunde(int userId, List<Land> länder)
        {
            W4NamensKlasse kundenNamen = new W4NamensKlasse(PaymentCompany ?? String.Empty, PaymentName, "", 40);
            //Name wird über Namensklasse aufgeteilt und nun zugeordnet

            if (kundenNamen.Name3.Length == 0 && PaymentAddress2.Length > 0)
            {
                kundenNamen.Name3 = PaymentAddress2;
            }

            string domainname;
            if (GlobalConfig.Freemails.Contains(Email.Split(new Char[] { '@' })[1].ToLower()) || Email == "")
            {
                domainname = "";
            }
            else
            {
                domainname = "www." + Email.Split('@')[1];
            }

            return new Kunde
            {
                KUND_N_KUNDGRUPPE = CustomerGroupId == 1 && PaymentCompany?.Length > 0 ? 2 : CustomerGroupId,
                KUND_N_PREISLISTNR = CustomerGroupId == 5 ? 2 : CustomerGroupId,
                KUND_A_SELEKTION6 = "KARLEY",
                KUND_N_VERTRETNUMM = 2,
                KUND_A_URL = domainname,
                KUND_N_ZAHLUNG = PaymentCodeId,
                KUND_N_LASTUSER = userId,
                KUND_A_EMAIL = Email,
                KUND_A_FAX = Fax,
                KUND_A_TEL1 = Telephone,
                KUND_A_ORT = PaymentCity,
                KUND_A_PLZ = PaymentPostcode,
                KUND_A_LAND = PaymentCountry,
                KUND_A_STRASSE = PaymentAddress1,
                KUND_A_NAME1 = kundenNamen.Name1,
                KUND_A_NAME2 = kundenNamen.Name2,
                KUND_A_NAME3 = StringErweiterung.MaxLength(kundenNamen.Name3, 60) ?? String.Empty,
                KUND_A_USTIDNR = PaymentTaxId,
                KUND_N_LIEFERUNG = Versandcode,
                KUND_L_MWST = länder.Any(x => x.WK5_LAND_L_ISTEULAND && x.LAND_A_ID == ShippingCountry), // MWST immer basis der Lieferanschrift
                KUND_L_BRUTTOKUNDE = länder.Any(x => x.WK5_LAND_L_ISTEULAND && x.LAND_A_ID == ShippingCountry), // MWST immer basis der Lieferanschrift
                KUND_A_ANREDE = Anrede,
                KUND_L_EUKUNDE = ShippingCountry != "DE" && länder.Any(x => x.WK5_LAND_L_ISTEULAND && x.LAND_A_ID == ShippingCountry),
                KUND_L_AUSLAND = länder.Any(x => !x.WK5_LAND_L_ISTEULAND && x.LAND_A_ID == ShippingCountry)
            };
        }

        /// <summary>
        /// Erstellt aus der ShopOrder einen Ansprechpartner der in der W4 eingefügt werden kann.
        /// <para>
        /// Diese Methode sollte nur dann aufgerufen werden, wenn die Daten der ShopOrder sich nicht mehr verändern können.
        /// </para>
        /// </summary>
        /// <returns></returns>
        public Ansprechpartner ToAnsprechpartner()
        {
            return new Ansprechpartner
            {
                PART_A_NAME = Lastname,
                PART_A_VORNAME = Firstname,
                PART_A_EMAIL = Email,
                PART_A_TELEFON = Telephone,
                PART_A_KUNDNR = CustomerId.ToString(), // Wir rufen die Methode erst auf, wenn wir die aktuellste Kundennummer haben
                PART_A_BRIEFANREDE = Anrede,
                PART_A_ADRESSTEXT = Lastname,
                PART_A_BEREICH = "Onlinebesteller"
            };
        }
        /// <summary>
        /// Erstellt aus der ShopOrder eine Lieferanschrift die in der W4 eingefügt werden kann.
        /// <para>
        /// Diese Methode sollte nur dann aufgerufen werden, wenn die Daten der ShopOrder sich nicht mehr verändern können.
        /// </para>
        /// </summary>
        /// <returns></returns>
        public Lieferanschrift? ToLieferanschrift(int userId, Kunde kunde, List<Land> länder)
        {
            // Wir haben nicht zwangsweise eine Lieferadresse, z.B. wenn der Kunde ausschließlich Artikel zum Download bestellt.
            if (ShippingCountry is null || ShippingPostcode is null || ShippingCity is null || ShippingAddress1 is null
                || (ShippingCompany is null && ShippingFirstname is null && ShippingLastname is null))
            {
                return null;
            }

            return new Lieferanschrift
            {
                KULA_A_KUNDNR = CustomerId.ToString(),
                KULA_A_NAME1 = ShippingCompany?.Length > 0 ? ShippingCompany : $"{ShippingFirstname} {ShippingLastname}", // Die W4 braucht immer einen Namen an erster Stelle, sonst kann nicht mehr upgedatet werden.
                KULA_A_NAME2 = ShippingCompany?.Length > 0 ? $"{ShippingFirstname} {ShippingLastname}" : "",
                KULA_A_STRASSE = ShippingAddress1,
                KULA_A_LAND = ShippingCountry,
                KULA_A_PLZ = ShippingPostcode,
                KULA_A_ORT = ShippingCity,
                KULA_A_EMAIL = Email,
                KULA_N_LASTUSER = userId,
                KULA_L_MWSTABWEICHEND = länder.Any(x => !x.WK5_LAND_L_ISTEULAND && x.LAND_A_ID == ShippingCountry), // Bei Lieferungen ins nicht EU Ausland wird keine Steuer berechnet.
                KULA_A_USTID = kunde.KUND_A_LAND != ShippingCountry ? PaymentTaxId : String.Empty,
                KULA_A_TEL = Telephone ?? string.Empty
            };
        }
        /// <summary>
        /// Erstellt aus der ShopOrder eine Rechnungsanschrift die in der W4 eingefügt werden kann.
        /// <para>
        /// Diese Methode sollte nur dann aufgerufen werden, wenn die Daten der ShopOrder sich nicht mehr verändern können.
        /// </para>
        /// </summary>
        /// <returns></returns>
        public Rechnungsanschrift ToRechnungsanschrift(int userId)
        {
            return new Rechnungsanschrift
            {
                KURE_A_KUNDNR = CustomerId.ToString(),
                KURE_A_NAME1 = PaymentCompany?.Length > 0 ? PaymentCompany : PaymentName,
                KURE_A_NAME2 = PaymentCompany?.Length > 0 ? PaymentName : String.Empty,
                KURE_A_STRASSE = PaymentAddress1,
                KURE_A_LAND = PaymentCountry,
                KURE_A_PLZ = PaymentPostcode,
                KURE_A_ORT = PaymentCity,
                KURE_A_EMAIL = Email,
                KURE_N_LASTUSER = userId,
                KURE_A_TEL = Telephone ?? string.Empty
            };
        }
    }
}
