using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace InABox.Core
{
    public class LoginCount : CoreAggregate<User, Login, Guid>
    {
        public override Expression<Func<Login, Guid>> Aggregate => x => x.ID;

        //public Expression<Func<Login, Guid>> Link => x => x.User.ID;

        public override AggregateCalculation Calculation => AggregateCalculation.Count;

        public override Dictionary<Expression<Func<Login, object>>, Expression<Func<User, object>>> Links =>
            new Dictionary<Expression<Func<Login, object>>, Expression<Func<User, object>>>
            {
                { Login => Login.User.ID, User => User.ID }
            };
    }

    public enum EmailType
    {
        None,
        Exchange,
        IMAP
    }

    public enum TwoFactorAuthenticationType
    {
        Email,
        SMS,
        GoogleAuthenticator
    }

    [UserTracking("Core Functionality")]
    public class User : Entity, IPersistent, IRemotable, IOneToMany<SecurityGroup>, ILicense<CoreLicense>
    {
        [EditorSequence(1)]
        [UniqueCodeEditor(Visible = Visible.Default, Editable = Editable.Enabled)]
        public virtual string UserID { get; set; }

        [EditorSequence(2)]
        [PasswordEditor(Visible = Visible.Hidden, Editable = Editable.Enabled, ViewButtonVisible = true)]
        public virtual string Password { get; set; }

        // Please note: this is a UTC time.
        [NullEditor]
        public DateTime PasswordExpiration { get; set; }

        [EditorSequence(3)]
        [TextBoxEditor(Visible = Visible.Default)]
        public string Description { get; set; }

        [EditorSequence(4)]
        [Caption("Network ID")]
        public string NetworkID { get; set; }

        [EditorSequence(5)]
        [PINEditor(Visible = Visible.Default)]
        public string PIN { get; set; }

        [EditorSequence(6)]
        public SecurityGroupLink SecurityGroup => InitializeField(ref _securityGroup, nameof(SecurityGroup));
        private SecurityGroupLink? _securityGroup;

        [EditorSequence(7)]
        [CheckBoxEditor(Visible = Visible.Default)]
        public bool Disabled { get; set; }

        public UserPlatform Platform => InitializeField(ref _platform, nameof(Platform));
        private UserPlatform? _platform;

        [EditorSequence("2FA", 1)]
        [CheckBoxEditor]
        public bool Use2FA { get; set; }

        [EditorSequence("2FA", 2)]
        [EnumLookupEditor(typeof(TwoFactorAuthenticationType))]
        [Caption("Type")]
        public TwoFactorAuthenticationType TwoFactorAuthenticationType { get; set; }

        [NullEditor]
        public byte[] AuthenticatorToken { get; set; }

        [EditorSequence("2FA", 3)]
        [TextBoxEditor]
        [Caption("Address")]
        public string Recipient2FA { get; set; }

        [EditorSequence("Email Settings", 1)]
        [EnumLookupEditor(typeof(EmailType), Visible = Visible.Hidden)]
        public EmailType EmailType { get; set; }

        [EditorSequence("Email Settings", 2)]
        [TextBoxEditor(Visible = Visible.Hidden)]
        public string EmailHost { get; set; }

        [EditorSequence("Email Settings", 3)]
        [IntegerEditor(Visible = Visible.Hidden)]
        public int EmailPort { get; set; }

        [EditorSequence("Email Settings", 4)]
        [TextBoxEditor(Visible = Visible.Hidden)]
        public string EmailDomain { get; set; }

        [EditorSequence("Email Settings", 6)]
        [TextBoxEditor(Visible = Visible.Default)]
        public string EmailAddress { get; set; }

        [EditorSequence("Email Settings", 7)]
        [TextBoxEditor(Visible = Visible.Hidden)]
        public string EmailUserID { get; set; }

        [EditorSequence("Email Settings", 8)]
        [PasswordEditor(Visible = Visible.Hidden)]
        public string EmailPassword { get; set; }

        [EditorSequence("Email Settings", 9)]
        [TextBoxEditor(Visible = Visible.Hidden)]
        public string SMTPHost { get; set; }

        [EditorSequence("Email Settings", 10)]
        [IntegerEditor(Visible = Visible.Hidden)]
        public int SMPTPort { get; set; }

        [EditorSequence("Email Settings", 11)]
        [TextBoxEditor(Visible = Visible.Hidden)]
        public string SMTPUserName { get; set; }

        [EditorSequence("Email Settings", 12)]
        [PasswordEditor(Visible = Visible.Hidden)]
        public string SMTPPassword { get; set; }

        [Aggregate(typeof(LoginCount))]
        [NullEditor]
        public int Logins { get; set; }

        static User()
        {
            DefaultColumns.Add<User>(x => x.UserID, width: 0, caption: "User ID");
            DefaultColumns.Add<User>(x => x.Password, width: 0, caption: "Password");
        }

        public override string ToString()
        {
            return UserID;
        }

        public static byte[] GenerateAuthenticationToken()
        {
            var random = new Random(DateTime.Now.Millisecond);
            var bytes = new byte[64];
            random.NextBytes(bytes);
            return bytes;
        }
    }
}