using Elwig.Models;
using Microsoft.Data.Sqlite;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Elwig.Helpers {
    public class ClientParameters {

        public enum Type { Matzen, Winzerkeller };

        public bool IsMatzen => Client == Type.Matzen;
        public bool IsWinzerkeller => Client == Type.Winzerkeller;
        public bool IsWolkersdorf => Client == Type.Winzerkeller && App.ZwstId == "W";
        public bool IsHaugsdorf => Client == Type.Winzerkeller && App.ZwstId == "H";
        public bool IsSitzendorf => Client == Type.Winzerkeller && App.ZwstId == "S";

        public string NameToken;
        public string NameShort;
        public string Name;
        public string? NameSuffix;
        public string NameType;
        public string NameFull => NameSuffix == null ? $"{Name} {NameType}" : $"{Name}, {NameSuffix}, {NameType}";
        public Type? Client;

        public PostalDest PostalDest {
            set {
                Plz = value.AtPlz.Plz;
                Ort = value.AtPlz.Ort.Name;
            }
        }
        public int Plz;
        public string Ort;
        public string Address;
        public string Sender1 => $"{NameShort} | {Address} | {Plz} {Ort}";
        public string Sender2;

        public string? Iban;
        public string? Bic;
        public string? UstIdNr;
        public string? LfbisNr;

        public string? PhoneNr;
        public string? FaxNr;
        public string? EmailAddress;
        public string? Website;

        public int DeliveryObligation;
        public int DeliveryRight;
        public decimal VatNormal;
        public decimal VatReduced;
        public decimal VatFlatRate;

        public string? TextDeliveryNote;

        public ClientParameters(AppDbContext ctx) : this(ctx.ClientParameters.ToDictionary(e => e.Param, e => e.Value)) { }

        public ClientParameters(Dictionary<string, string?> parameters) {
            try {
                NameToken = parameters["CLIENT_NAME_TOKEN"] ?? throw new KeyNotFoundException();
                NameShort = parameters["CLIENT_NAME_SHORT"] ?? throw new KeyNotFoundException();
                Name = parameters["CLIENT_NAME"] ?? throw new KeyNotFoundException();
                NameSuffix = parameters.GetValueOrDefault("CLIENT_NAME_SUFFIX");
                NameType = parameters["CLIENT_NAME_TYPE"] ?? throw new KeyNotFoundException();
                switch (Name) {
                    case "Winzergenossenschaft für Matzen und Umgebung": Client = Type.Matzen; break;
                    case "Winzerkeller im Weinviertel": Client = Type.Winzerkeller; break;
                };

                Plz = int.Parse(parameters["CLIENT_PLZ"] ?? "");
                Ort = parameters["CLIENT_ORT"] ?? throw new KeyNotFoundException();
                Address = parameters["CLIENT_ADDRESS"] ?? throw new KeyNotFoundException();
                PhoneNr = parameters.GetValueOrDefault("CLIENT_PHONE");
                FaxNr = parameters.GetValueOrDefault("CLIENT_FAX");
                EmailAddress = parameters.GetValueOrDefault("CLIENT_EMAIL");
                Website = parameters.GetValueOrDefault("CLIENT_WEBSITE");
                LfbisNr = parameters.GetValueOrDefault("CLIENT_LFBISNR");
                UstIdNr = parameters.GetValueOrDefault("CLIENT_USTIDNR");
                Bic = parameters.GetValueOrDefault("CLIENT_BIC");
                Iban = parameters.GetValueOrDefault("CLIENT_IBAN");

                DeliveryObligation = int.Parse(parameters["DELIVERY_OBLIGATION"] ?? "");
                DeliveryRight = int.Parse(parameters["DELIVERY_RIGHT"] ?? "");
                VatNormal = decimal.Parse((parameters["VAT_NORMAL"] ?? "").Replace(".", ","));
                VatReduced = decimal.Parse((parameters["VAT_REDUCED"] ?? "").Replace(".", ","));
                VatFlatRate = decimal.Parse((parameters["VAT_FLATRATE"] ?? "").Replace(".", ","));

                Sender2 = parameters.GetValueOrDefault("DOCUMENT_SENDER") ?? "";
                TextDeliveryNote = parameters.GetValueOrDefault("TEXT_DELIVERYNOTE");
            } catch {
                throw new KeyNotFoundException();
            }
        }

        private IEnumerable<(string, string?)> GetParamValues() {
            return new (string, string?)[] {
                ("CLIENT_NAME_TOKEN", NameToken),
                ("CLIENT_NAME_SHORT", NameShort),
                ("CLIENT_NAME", Name),
                ("CLIENT_NAME_SUFFIX", NameSuffix),
                ("CLIENT_NAME_TYPE", NameType),
                ("CLIENT_PLZ", Plz.ToString()),
                ("CLIENT_ORT", Ort),
                ("CLIENT_ADDRESS", Address),
                ("CLIENT_PHONE", PhoneNr),
                ("CLIENT_FAX", FaxNr),
                ("CLIENT_EMAIL", EmailAddress),
                ("CLIENT_WEBSITE", Website),
                ("CLIENT_LFBISNR", LfbisNr),
                ("CLIENT_USTIDNR", UstIdNr),
                ("CLIENT_BIC", Bic),
                ("CLIENT_IBAN", Iban),
                ("DELIVERY_OBLIGATION", DeliveryObligation.ToString()),
                ("DELIVERY_RIGHT", DeliveryRight.ToString()),
                ("VAT_NORMAL", VatNormal.ToString().Replace(",", ".")),
                ("VAT_REDUCED", VatReduced.ToString().Replace(",", ".")),
                ("VAT_FLATRATE", VatFlatRate.ToString().Replace(",", ".")),
                ("DOCUMENT_SENDER", Sender2),
                ("TEXT_DELIVERYNOTE", TextDeliveryNote),
            };
        }

        public async Task UpdateValues() {
            using var cnx = await AppDbContext.ConnectAsync();
            using var cmd = cnx.CreateCommand();
            var pv = GetParamValues();
            cmd.CommandText = "INSERT INTO client_parameter (param, value) VALUES " +
                string.Join(", ", pv.Select((pv, i) => $"(@p{i}, " + (pv.Item2 != null ? $"@v{i}" : "NULL") + ")")) +
                " ON CONFLICT DO UPDATE SET value = excluded.value";

            int i = 0;
            foreach (var (p, v) in pv) {
                cmd.Parameters.Add(new SqliteParameter($"@p{i}", p));
                if (v != null)
                    cmd.Parameters.Add(new SqliteParameter($"@v{i}", v));
                i++;
            }

            await cmd.ExecuteNonQueryAsync();
        }
    }
}