using GreenTree.Strohrmann.ERP.Domain.Model;
using GreenTree.Strohrmann.ERP.Services.Authorization;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace GreenTree.Strohrmann.ERP.Services.Authentication
{
    public class DbContextAuthenticationService : IAuthenticationService
    {
        #region DI fields

        // The global DbContext
        private readonly ERPDbContext _eRPDbContext;

        // The global HttpContext accessor
        private readonly IHttpContextAccessor _httpContextAccessor;

        // The global administration options
        private readonly AdministrationOptions _administrationOptions;

        #endregion

        #region Ctor

        /// <summary>
        /// Initializes a new instance of the DbContextAuthenticationService class
        /// </summary>
        /// <param name="eRPDbContext">Global DbContext.</param>
        /// <param name="httpContextAccessor">Global HTTP context accessor.</param>
        /// <param name="administrationOptions">Global administration options.</param>
        public DbContextAuthenticationService(
            ERPDbContext eRPDbContext,
            IHttpContextAccessor httpContextAccessor,
            AdministrationOptions administrationOptions)
        {
            _eRPDbContext = eRPDbContext;
            _httpContextAccessor = httpContextAccessor;
            _administrationOptions = administrationOptions;
        }

        #endregion

        #region Implementation

        /// <summary>
        /// Authenticate and sign user in
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="username">The username.</param>
        /// <param name="isPersistent">The login persistence.</param>
        public async void SignIn(string username, bool isPersistent = false)
        {
            var user = _eRPDbContext.Users
                .FirstOrDefault(u => u.Accountname == username || u.MailAddress == username);

            if (user == null)
                throw new Exception(
                    String.Format("Der Benutzer \"{0}\" kann nicht gefunden werden.", username));

            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.NameIdentifier, user.Accountname),
                new Claim(ClaimTypes.Name, String.Format("{0}, {1}", user.Lastname, user.Forename)),
                new Claim(ClaimTypes.Email, user.MailAddress)
            };

            if (user.Birthdate.HasValue)
                claims.Add(new Claim(ClaimTypes.DateOfBirth, user.Birthdate.Value.ToString("dd.MM.yyyy")));

            foreach (var policy in user.Policies)
            {
                claims.Add(new Claim("Policy", policy.PolicyName));
            }

            var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
            var principal = new ClaimsPrincipal(identity);

            var authProperties = new AuthenticationProperties
            {
                AllowRefresh = true,
                IsPersistent = isPersistent,
                IssuedUtc = DateTimeOffset.UtcNow
            };

            await _httpContextAccessor.HttpContext.SignInAsync(
                CookieAuthenticationDefaults.AuthenticationScheme,
                principal,
                authProperties);
        }

        /// <summary>
        /// Authenticate and sign user in
        /// </summary>
        /// <param name="username">The username.</param>
        /// <param name="isPersistent">The login persistence.</param>
        public async void SignInAdmin(bool isPersistent = false)
        {
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.NameIdentifier, _administrationOptions.Administrator),
                new Claim(ClaimTypes.Name, _administrationOptions.Administrator)
            };

            var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
            var principal = new ClaimsPrincipal(identity);

            var authProperties = new AuthenticationProperties
            {
                AllowRefresh = true,
                IsPersistent = isPersistent,
                IssuedUtc = DateTimeOffset.UtcNow
            };

            await _httpContextAccessor.HttpContext.SignInAsync(
                CookieAuthenticationDefaults.AuthenticationScheme,
                principal,
                authProperties);
        }

        /// <summary>
        /// Sign user out
        /// </summary>
        /// <param name="httpContext"></param>
        public async void SignOut()
        {
            await _httpContextAccessor.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        }

        #endregion
    }
}
