using CoviDok.Api;
using CoviDok.Api.Request;
using CoviDok.Api.Response;
using CoviDok.Data.MySQL;
using CoviDok.Data.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace CoviDok.BLL.User
{
    public class Auth
    {
        private static  string emailRegex = @"(@)(.+)$";
        private static string pwRegex = @"^(?=.{6,})(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=?!]).*$"; //8 hosszú, kis és nagybetű, különleges karakter
        private static readonly MySqlContext context = new MySqlContext();

        public static async Task<AuthIdentity> AuthenticateUser(string Email, string Password)
        {
            if (!Regex.IsMatch(Email, emailRegex, RegexOptions.IgnoreCase)) throw new FormatException();

            List<RoleUser> users = new List<RoleUser>();
            await Task.Run(() =>
            {
                var us = from u in context.RoleUsers where u.Email == Email select u;
                users.AddRange(us);
            });

            if (users.Count != 1) throw new KeyNotFoundException();
            RoleUser user = users[0];

            if (user.CheckPassword(Password)) { 
                return  new AuthIdentity
                {
                    FirstName = user.FirstName,
                    LastName = user.LastName,
                    Role = user.Role,
                    UserId = user.Id
                };
            }
            return null;
        }

        public static bool CheckEmail(string Email) {
            return context.RoleUsers.Any(e => e.Email == Email);
        }

        public static GenericResponse ValidateRegistration(string Email, string Password)
        {
            GenericResponse genericResponse = new GenericResponse();

            if (CheckEmail(Email))
            {
                genericResponse.Status = Status.Error;
                genericResponse.Body["reason"] = Email + " is already registered!";
                return genericResponse;
            }
            if (!Regex.IsMatch(Email, emailRegex, RegexOptions.IgnoreCase))
            {
                genericResponse.Status = Status.Error;
                genericResponse.Body["reason"] = Email + " is not a valid email address!";
                return genericResponse;
            }
            if (!Regex.IsMatch(Password, pwRegex, RegexOptions.IgnoreCase)) {
                genericResponse.Status = Status.Error;
                genericResponse.Body["reason"] = "Password does not meet complexity requirements!";
                return genericResponse;
            }
            return genericResponse;
        }

        public static async Task<GenericResponse> CreateUser(AuthRegistration registration) {
            GenericResponse response = new GenericResponse();
            switch (registration.Role)
            {
                case Role.Ast:
                    Assistant ast = new Assistant { 
                        FirstName = registration.FirstName,
                        LastName = registration.LastName,
                        Email = registration.Email,
                        Password = RoleUser.GetHashString(registration.Password),
                        Role = Role.Ast,
                        Phone = registration.Phone
                    };
                    context.Assistants.Add(ast);
                    await context.SaveChangesAsync();
                    response.Body["id"] = ast.Id.ToString();
                    break;
                case Role.Doc:
                    Doctor doc = new Doctor {
                        FirstName = registration.FirstName,
                        LastName = registration.LastName,
                        Email = registration.Email,
                        Password = RoleUser.GetHashString(registration.Password),
                        Role = Role.Doc,
                        Phone = registration.Phone
                    };
                    context.Doctors.Add(doc);
                    await context.SaveChangesAsync();
                    response.Body["id"] = doc.Id.ToString();
                    break;
                case Role.Par:
                    Parent par = new Parent
                    {
                        FirstName = registration.FirstName,
                        LastName = registration.LastName,
                        Email = registration.Email,
                        Password = RoleUser.GetHashString(registration.Password),
                        Role = Role.Par,
                        Phone = registration.Phone
                    };
                    context.Parents.Add(par);
                    await context.SaveChangesAsync();
                    response.Body["id"] = par.Id.ToString();
                    break;
            }
            return response;
        }
    }
}