using Elwig.Helpers;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;

namespace Elwig.Models.Entities {
    [Table("member"), PrimaryKey("MgNr")]
    public class Member : IAddress {
        [Column("mgnr")]
        public int MgNr { get; set; }

        [Column("predecessor_mgnr")]
        public int? PredecessorMgNr { get; set; }

        [Column("name")]
        public required string Name { get; set; }

        [Column("prefix")]
        public string? Prefix { get; set; }

        [Column("given_name")]
        public string? GivenName { get; set; }

        [Column("middle_names")]
        public string? MiddleName { get; set; }
        [NotMapped]
        public string[] MiddleNames {
            get => (MiddleName != null) ? MiddleName.Split(" ") : [];
            set => MiddleName = (value.Length > 0) ? string.Join(" ", value) : null;
        }

        [Column("suffix")]
        public string? Suffix { get; set; }

        [Column("attn")]
        public string? ForTheAttentionOf { get; set; }

        [NotMapped]
        public string FullName => IsJuridicalPerson ? Name : string.Join(" ", ((string?[])[Prefix, GivenName, MiddleName, Name, Suffix]).Where(s => !string.IsNullOrWhiteSpace(s)));
        [NotMapped]
        public string ShortName => (!string.IsNullOrWhiteSpace(GivenName) ? $"{GivenName} " : "") + Name;
        [NotMapped]
        public string AdministrativeName => AdministrativeName1 + (!string.IsNullOrWhiteSpace(AdministrativeName2) ? $" {AdministrativeName2}" : "");
        [NotMapped]
        public string AdministrativeName1 => IsJuridicalPerson ? Name : Name.Replace('ß', 'ẞ').ToUpper();
        [NotMapped]
        public string? AdministrativeName2 => IsJuridicalPerson ? null : string.Join(" ", ((string?[])[Prefix, GivenName, MiddleName, Suffix]).Where(s => !string.IsNullOrWhiteSpace(s)));

        [Column("birthday")]
        public string? Birthday { get; set; }

        [Column("entry_date")]
        public string? EntryDateString { get; set; }
        [NotMapped]
        public DateOnly? EntryDate {
            get => EntryDateString != null ? DateOnly.ParseExact(EntryDateString, "yyyy-MM-dd") : null;
            set => EntryDateString = value?.ToString("yyyy-MM-dd");
        }

        [Column("exit_date")]
        public string? ExitDateString { get; set; }
        [NotMapped]
        public DateOnly? ExitDate {
            get => ExitDateString != null ? DateOnly.ParseExact(ExitDateString, "yyyy-MM-dd") : null;
            set => ExitDateString = value?.ToString("yyyy-MM-dd");
        }

        [Column("business_shares")]
        public int BusinessShares { get; set; }

        [Column("accounting_nr")]
        public string? AccountingNr { get; set; }

        [Column("zwstid")]
        public string? ZwstId { get; set; }

        [Column("lfbis_nr")]
        public string? LfbisNr { get; set; }

        [Column("ustid_nr")]
        public string? UstIdNr { get; set; }

        [Column("juridical_pers")]
        public bool IsJuridicalPerson { get; set; }

        [Column("volllieferant")]
        public bool IsVollLieferant { get; set; }

        [Column("buchführend")]
        public bool IsBuchführend { get; set; }

        [Column("organic")]
        public bool IsOrganic { get; set; }

        [Column("funktionär")]
        public bool IsFunktionär { get; set; }

        [Column("active")]
        public bool IsActive { get; set; }

        [Column("deceased")]
        public bool IsDeceased { get; set; }

        [Column("iban")]
        public string? Iban { get; set; }

        [Column("bic")]
        public string? Bic { get; set; }

        [Column("country")]
        public int CountryNum { get; set; }

        [Column("postal_dest")]
        public string PostalDestId { get; set; } = null!;

        [Column("address")]
        public string Address { get; set; } = null!;

        [Column("default_kgnr")]
        public int? DefaultKgNr { get; set; }

        [Column("contact_postal")]
        public bool ContactViaPost { get; set; }

        [Column("contact_email")]
        public bool ContactViaEmail { get; set; }

        [Column("comment")]
        public string? Comment { get; set; }

        [ForeignKey("PredecessorMgNr")]
        public virtual Member? Predecessor { get; private set; }

        [ForeignKey("CountryNum")]
        public virtual Country Country { get; private set; } = null!;

        [ForeignKey("CountryNum, PostalDestId")]
        public virtual PostalDest PostalDest { get; private set; } = null!;

        [ForeignKey("DefaultKgNr")]
        public virtual WbKg? DefaultWbKg { get; private set; }
        [NotMapped]
        public AT_Kg? DefaultKg => DefaultWbKg?.AtKg;

        [Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
        public long CTime { get; set; }
        [NotMapped]
        public DateTime CreatedAt {
            get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
            set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
        }

        [Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
        public long MTime { get; set; }
        [NotMapped]
        public DateTime ModifiedAt {
            get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
            set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
        }

        [Column("xtime")]
        public long? XTime { get; set; }
        [NotMapped]
        public DateTime? ExportedAt {
            get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime;
            set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
        }

        [Column("itime")]
        public long? ITime { get; set; }
        [NotMapped]
        public DateTime? ImportedAt {
            get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime;
            set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
        }

        [ForeignKey("ZwstId")]
        public virtual Branch? Branch { get; private set; }

        [InverseProperty(nameof(AreaCom.Member))]
        public virtual ICollection<AreaCom> AreaCommitments { get; private set; } = null!;

        public IQueryable<AreaCom> ActiveAreaCommitments(AppDbContext ctx, int? year = null) {
            return ctx.AreaCommitments.Where(c => c.MgNr == MgNr).Where(Utils.ActiveAreaCommitments(year ?? Utils.CurrentYear));
        }

        [InverseProperty(nameof(BillingAddr.Member))]
        public virtual BillingAddr? BillingAddress { get; private set; }

        [InverseProperty(nameof(Delivery.Member))]
        public virtual ICollection<DeliveryAncmt> Announcements { get; private set; } = null!;

        [InverseProperty(nameof(Delivery.Member))]
        public virtual ICollection<Delivery> Deliveries { get; private set; } = null!;

        [InverseProperty(nameof(Credit.Member))]
        public virtual ICollection<Credit> Credits { get; private set; } = null!;

        [InverseProperty(nameof(MemberTelNr.Member))]
        public virtual ICollection<MemberTelNr> TelephoneNumbers { get; private set; } = null!;

        [InverseProperty(nameof(MemberEmailAddr.Member))]
        public virtual ICollection<MemberEmailAddr> EmailAddresses { get; private set; } = null!;

        public string FullAddress => $"{Address}, {PostalDest.AtPlz?.Plz} {PostalDest.AtPlz?.Ort.Name}";

        public int SearchScore(IEnumerable<string> keywords) {
            return Utils.GetSearchScore([
                Name, MiddleName, GivenName,
                BillingAddress?.FullName,
                Comment,
            ], keywords);
        }
    }
}
