using Kimuser.Domain;
using Kimuser.Domain.SystemUsers;
using Kimuser.Dto;
using Kimuser.Dto.Items.Roles;
using Kimuser.Dto.Items.SystemUsers;
using Kimuser.Dto.Models.SystemUsers;
using Kimuser.Dto.Results;
using Kimuser.Dto.Results.SystemUsers;
using Kimuser.Dto.SmartTable;
using Kimuser.Infrastructure.Helpers;
using Kimuser.Infrastructure.Repositories;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Kimuser.Services
{
    public interface ISystemUserService
    {
        Task<SystemUserModel> GetUserAsync(int userId);

        /// <summary>
        /// Tạo / cập nhật SystemUser
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task<SystemUserResult> CreateOrUpdate(SystemUserModel model);

        Task<SmartTableResult<SystemUserItem>> Search(SmartTableParam param);
        Task<SmartTableResult<SystemUserLocalItem>> LocalSearch(SmartTableParam param);
        Task<List<string>> GetUserRolesAsync(int userId);
        Task<SystemUserResult> AddRoleToUserAsync(int userId, List<string> roles);
        Task<List<string>> GetRolesOfUser(int userId);
        Task<ChangePasswordResult> ChangePassword(ChangePasswordModel model);
        Task<ChangePasswordResult> SetPassword(ChangePasswordModel model);
        Task<BaseResult> UnLock(LockModel model);
        Task<BaseResult> Lock(LockModel model);
    }

    public class SystemUserService : ISystemUserService
    {
        private readonly IUserRepository<SystemUser> _systemUserRepository;
        private readonly UserManager<User> _userManager;
        private readonly RoleManager<Role> _roleManager;
        public SystemUserService(IUserRepository<SystemUser> systemUserRepository, UserManager<User> userManager, RoleManager<Role> roleManager)
        {
            _systemUserRepository = systemUserRepository;
            _userManager = userManager;
            _roleManager = roleManager;
        }



        public async Task<SmartTableResult<SystemUserItem>> Search(SmartTableParam param)
        {
            var query = _systemUserRepository.Query();
            if (param.Search.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;
                if (search.Keyword != null)
                {
                    string keyword = search.Keyword;
                    keyword = keyword.Trim().ToLower();
                    query = query.Where(x => x.UserName.ToLower().Contains(keyword) || x.FullName.ToLower().Contains(keyword) || x.Email.ToLower().Contains(keyword));
                }
                if (search.CreatedStart != null && search.CreatedEnd != null)
                {
                    DateTimeOffset start = search.CreatedStart;
                    DateTimeOffset end = search.CreatedEnd;
                    query = query.Where(x => (x.CreatedTime >= start) && (x.CreatedTime <= end));
                }

            }
            param.Sort = new Sort() { Predicate = "Id", Reverse = true };
            var gridData = await query.ToSmartTableResultAsync(param, x => x.ToItem());
            return gridData;
        }

        public async Task<SmartTableResult<SystemUserLocalItem>> LocalSearch(SmartTableParam param)
        {
            var query = _systemUserRepository.Query();
            if (param.Search.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;
                if (search.Keyword != null)
                {
                    string keyword = search.Keyword;
                    keyword = keyword.Trim().ToLower();
                    query = query.Where(x => x.UserName.ToLower().Contains(keyword) || x.FullName.ToLower().Contains(keyword) || x.Email.ToLower().Contains(keyword));
                }
                if (search.CreatedStart != null && search.CreatedEnd != null)
                {
                    DateTimeOffset start = search.CreatedStart;
                    DateTimeOffset end = search.CreatedEnd;
                    DateTimeOffset startParam = start.StartOfDay();
                    DateTimeOffset endParam = end.EndOfDay();
                    query = query.Where(x => (x.CreatedTime >= startParam) && (x.CreatedTime <= endParam));


                }

            }
            param.Sort = new Sort() { Predicate = "Id", Reverse = true };
            var gridData = await query.ToSmartTableResultAsync(param, x => x.ToLocalItem());
            return gridData;
        }

        public async Task<SystemUserResult> CreateOrUpdate(SystemUserModel model)
        {
            var systemUser = model.ToEntity();

            //Cập nhật thông tin chung của thực thể
            //systemUser = systemUser.UpdateCommonInt();




            if (systemUser.Id > 0)
            {
                //Cập nhật
                return await Update(systemUser);
            }
            else
            {
                //Thêm mới
                return await Create(systemUser, model.Password);
            }
        }
        

        private async Task<SystemUserResult> Update(SystemUser systemUser)
        {
            var result = new SystemUserResult() { Result = Result.Success };
            var systemUserForUpdate = _systemUserRepository.Query().FirstOrDefault(c => c.Id == systemUser.Id);
            if (systemUserForUpdate == null || systemUser.Id <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy bài viết yêu cầu!";
                return result;
            }

            try
            {
                //Cập nhật thông tin của bài viết
                systemUserForUpdate.FullName = systemUser.FullName.Trim();
                systemUserForUpdate.Address = systemUser.Address.Trim();
                systemUserForUpdate.Gender = systemUser.Gender;
                systemUserForUpdate.FacebookContact = systemUser.FacebookContact;
                systemUserForUpdate.ZaloContact = systemUser.ZaloContact;
                systemUserForUpdate.PhoneNumber = systemUser.PhoneNumber;
                systemUserForUpdate.BranchId = systemUser.BranchId;
                systemUserForUpdate.DateOfBirth = systemUser.DateOfBirth;
                systemUserForUpdate.Position = systemUser.Position;
                systemUser.UpdatedTime = DateTimeOffset.Now;
                //Cập nhật thông tin chung của thực thể
                //systemUserForUpdate = systemUserForUpdate.UpdateCommonInt();

                _systemUserRepository.Update(systemUserForUpdate);
                result.Id = systemUserForUpdate.Id;
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.ToString();
            }

            return result;
        }

        /// <summary>
        /// Tạo bài viết
        /// </summary>
        /// <param name="systemUser"></param>
        /// <returns></returns>
        private async Task<SystemUserResult> Create(SystemUser systemUser, string password = "")
        {
            var result = new SystemUserResult();
            try
            {
                systemUser.CreatedTime = DateTimeOffset.Now;
                systemUser.UpdatedTime = DateTimeOffset.Now;
                var registerResult = await _userManager.CreateAsync(systemUser, password);
                if (registerResult.Succeeded)
                {
                    result.Id = systemUser.Id;
                }
                else
                {
                    result.Result = Result.Failed;
                    foreach (var error in registerResult.Errors)
                    {
                        if (error.Code == "DuplicateUserName")
                            result.Message = "Tài khoản đã tồn tại";
                        else if (error.Code == "DuplicateEmail")
                            result.Message = "Địa chỉ Email đã tồn tại";
                        else
                            result.Message = error.Description;

                    }
                }

            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.ToString();
                result.Id = 0;
            }
            return result;
        }


        public async Task<SystemUserModel> GetUserAsync(int userId)
        {
            var model = new SystemUserModel();
            if (userId <= 0) return model;
            var systemUser = await _systemUserRepository.Query().FirstOrDefaultAsync(c => c.Id == userId);
            if (systemUser != null && systemUser.Id > 0)
            {
                model = systemUser.ToModel();

            }
            return model;
        }
        public async Task<List<string>> GetUserRolesAsync(int userId)
        {
            var roleList = new List<string>();
            var model = new SystemUserModel();
            if (userId <= 0) return roleList;
            var systemUser = await _systemUserRepository.Query().FirstOrDefaultAsync(c => c.Id == userId);
            if (systemUser != null && systemUser.Id > 0)
            {
                roleList = (await _userManager.GetRolesAsync(systemUser)).ToList();
            }
            return roleList;
        }

        public async Task<SystemUserResult> AddRoleToUserAsync(int userId, List<string> roles)
        {
            var result = new SystemUserResult();
            var model = new SystemUserModel();
            if (userId <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Thông tin người dùng không hợp lệ";
            }
            var systemUser = await _systemUserRepository.Query().FirstOrDefaultAsync(c => c.Id == userId);
            if (systemUser != null && systemUser.Id > 0)
            {
                var identityResult = await _userManager.AddToRolesAsync(systemUser, roles);
                if (!identityResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = String.Join("\n", identityResult.Errors.Select(e => e.Description));
                }
            }
            return result;
        }

        public async Task<List<string>> GetRolesOfUser(int userId)
        {
            var result = new List<string>();
            if (userId <= 0) return result;
            var systemUser = await _systemUserRepository.Query().FirstOrDefaultAsync(c => c.Id == userId);
            if (systemUser != null && systemUser.Id > 0)
            {
                result = (await _userManager.GetRolesAsync(systemUser)).ToList();
            }

            return result;
        }

        public async Task<ChangePasswordResult> ChangePassword(ChangePasswordModel model)
        {
            var result = new ChangePasswordResult();
            if (model.UserId <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Mã người dùng không hợp lệ";
                return result;
            }
            if (model.NewPassword.CompareTo(model.RetypeNewPassword) != 0)
            {
                result.Result = Result.Failed;
                result.Message = "Mật khẩu và xác nhận mật khẩu không khớp";
                return result;
            }
            var systemUser = await _systemUserRepository.Query().FirstOrDefaultAsync(c => c.Id == model.UserId);
            if (systemUser != null && systemUser.Id > 0)
            {
                var identityResult = await _userManager.ChangePasswordAsync(systemUser, model.CurrentPassword, model.NewPassword);
                if (!identityResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = String.Join("\n", identityResult.Errors.Select(e => e.Description));
                    return result;
                }
                systemUser.Password = model.NewPassword;
                _systemUserRepository.Update(systemUser);
            }
            return result;
        }

        public async Task<ChangePasswordResult> SetPassword(ChangePasswordModel model)
        {
            var result = new ChangePasswordResult();
            if (model.UserId <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Mã người dùng không hợp lệ";
                return result;
            }
            if (model.NewPassword.CompareTo(model.RetypeNewPassword) != 0)
            {
                result.Result = Result.Failed;
                result.Message = "Mật khẩu và xác nhận mật khẩu không khớp";
                return result;
            }
            var systemUser = await _systemUserRepository.Query().FirstOrDefaultAsync(c => c.Id == model.UserId);
            if (systemUser != null && systemUser.Id > 0)
            {
                var identityResult = await _userManager.RemovePasswordAsync(systemUser);
                if (!identityResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = String.Join("\n", identityResult.Errors.Select(e => e.Description));
                    return result;
                }
                identityResult = await _userManager.AddPasswordAsync(systemUser,model.NewPassword);
                if (!identityResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = String.Join("\n", identityResult.Errors.Select(e => e.Description));
                    return result;
                }
                systemUser.Password = model.NewPassword;
                _systemUserRepository.Update(systemUser);
            }
            else
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy người dùng yêu cầu";
            }
            return result;
        }

        public async Task<BaseResult> Lock(LockModel model)
        {
            var result = new BaseResult();
            if (model.UserId <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Mã người dùng không hợp lệ";
                return result;
            }
            
            var systemUser = await _systemUserRepository.Query().FirstOrDefaultAsync(c => c.Id == model.UserId);
            if (systemUser != null && systemUser.Id > 0)
            {
                var identityResult = await _userManager.SetLockoutEnabledAsync(systemUser,true);
                if (!identityResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = String.Join("\n", identityResult.Errors.Select(e => e.Description));
                    return result;
                }
                identityResult = await _userManager.SetLockoutEndDateAsync(systemUser, DateTimeOffset.Now.AddYears(20));
                if (!identityResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = String.Join("\n", identityResult.Errors.Select(e => e.Description));
                    return result;
                }
                
            }
            else
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy người dùng yêu cầu";
            }
            return result;
        }

        public async Task<BaseResult> UnLock(LockModel model)
        {
            var result = new BaseResult();
            if (model.UserId <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Mã người dùng không hợp lệ";
                return result;
            }

            var systemUser = await _systemUserRepository.Query().FirstOrDefaultAsync(c => c.Id == model.UserId);
            if (systemUser != null && systemUser.Id > 0)
            {
                
                var identityResult = await _userManager.SetLockoutEndDateAsync(systemUser, DateTimeOffset.Now);
                if (!identityResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = String.Join("\n", identityResult.Errors.Select(e => e.Description));
                    return result;
                }

            }
            else
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy người dùng yêu cầu";
            }
            return result;
        }
    }
}
