using Lada.Framework.Data.Domains.Identity;
using Lada.Framework.Data.Enums;
using Lada.Framework.DTO;
using Lada.Framework.DTO.SmartTable;
using Lada.Framework.Infrastructures.Helpers;
using Ladaer.BackEnd.Infrastructures.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Identity;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Itentity;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Users;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Users;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

namespace Ladaer.BackEnd.Infrastructures.Services.Identity
{
    public interface IRoleService
    {
        Task<SmartTableResult<RoleItem>> SearchAsync(SmartTableParam param);
        Task<List<RoleItem>> GetRolesAsync(int currentUserId);
        Task<RoleModel> GetByIdAsync(int roleId);
        Task<BaseResult> CreateOrUpdateAsync(RoleModel model);
        Task<BaseResult> DeleteAsync(int roleId);
        Task<BaseResult> SetRoleAsync(SetRoleModel model);

    }

    public class RoleService : IRoleService
    {
        private readonly RoleManager<Role> _roleManager;
        private readonly UserManager<User> _userManager;
        public RoleService(RoleManager<Role> roleManager, UserManager<User> userManager)
        {
            _roleManager = roleManager;
            _userManager = userManager;
        }

        

        public async Task<RoleModel> GetByIdAsync(int roleId)
        {
            var result = new RoleModel();
            var role = await _roleManager.FindByIdAsync(roleId.ToString());

            if (role != null && role.Id > 0)
            {
                result = role.ToModel();
            }
            return result;
        }

        public async Task<List<RoleItem>> GetRolesAsync(int currentUserId)
        {
            var result = new List<RoleItem>();
            var exceptRoles = new List<string>() { "Founder","Co-Founder" };
            var currentUser = await _userManager.FindByIdAsync(currentUserId.ToString());
            if (currentUser!=null && currentUser.Id > 0)
            {
                var currentRoles = await _userManager.GetRolesAsync(currentUser);
                if (currentRoles != null && currentRoles.Any(r => r == "Founder"))
                {
                    //Nếu là founder thì cho phép lấy ra toàn bộ
                    exceptRoles = new List<string>();
                }
                result = await _roleManager.Roles.Where(r => r.Name != null && !exceptRoles.Contains(r.Name)).Select(r => r.ToItem()).ToListAsync();
            }
            return result;
        }

        public async Task<SmartTableResult<RoleItem>> SearchAsync(SmartTableParam param)
        {
            var result = new SmartTableResult<RoleItem>();
            var query = _roleManager.Roles;
            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 => (!string.IsNullOrEmpty(x.Name) && x.Name.ToLower().Contains(keyword)) ||
                                        (!string.IsNullOrEmpty(x.Description) && x.Description.ToLower().Contains(keyword)) ||
                                        (!string.IsNullOrEmpty(x.CreatedByUserName) && x.CreatedByUserName.ToLower().Contains(keyword)) ||
                                        (!string.IsNullOrEmpty(x.UpdatedByUserName) && x.UpdatedByUserName.ToLower().Contains(keyword))
                                    );
                }
                if (search.CreatedStart != null && search.CreatedEnd != null)
                {
                    DateTimeOffset start = search.CreatedStart;
                    DateTimeOffset end = search.CreatedEnd;
                    var startParam = start.StartOfDay();
                    var endParam = end.EndOfDay();
                    query = query.Where(x => (x.CreatedTime >= startParam) && (x.CreatedTime <= endParam));
                }

            }
            param.Sort = new Sort() { Predicate = "Id", Reverse = true };

            result = await query.ToSmartTableResultAsync(param, x => x.ToItem());
            return result;
        }

        public async Task<BaseResult> DeleteAsync(int roleId)
        {
            var result = new BaseResult();
            var role = await _roleManager.FindByIdAsync(roleId.ToString());
            if (role != null && role.Id > 0)
            {
                var identityResult = await _roleManager.DeleteAsync(role);
                if (!identityResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = string.Join("\n", identityResult.Errors.Select(e => e.Description));
                }
            }
            return result;
        }

        public async Task<BaseResult> CreateOrUpdateAsync(RoleModel model)
        {
            var result = new BaseResult();

            if (model.Id > 0)
            {
                result = await UpdateRoleAsync(model);
            }
            else
            {
                result = await AddRoleAsync(model);
            }


            return result;
        }

        public async Task<BaseResult> SetRoleAsync(SetRoleModel model)
        {
            var result = new BaseResult();
            var user = await _userManager.FindByIdAsync(model.Id.ToString());

            if (user != null && user.Id > 0)
            {
                var currentRoles = await _userManager.GetRolesAsync(user);
                //Xóa toàn bộ role của người dùng đi
                if (currentRoles.Count > 0)
                {
                    foreach (var item in currentRoles)
                    {
                        await _userManager.RemoveFromRoleAsync(user, item);
                    }
                }
                var identityResult = await _userManager.AddToRoleAsync(user, model.Role);
                if (!identityResult.Succeeded)
                {
                    return await BuildError(identityResult);
                }
                return await UpdateCommonUser(user, model.UpdatedBy, model.UpdatedByUserName);

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


        #region Utilities
        private async Task<BaseResult> AddRoleAsync(RoleModel model)
        {
            var result = new BaseResult();
            var currentTime = DateTimeHelper.CurrentTime();
            var role = new Role()
            {
                Name = model.Name,
                Description = model.Description,
                CreatedBy = model.UpdatedBy,
                UpdatedBy = model.UpdatedBy,
                CreatedByUserName = model.UpdatedByUserName,
                UpdatedByUserName = model.UpdatedByUserName,
                CreatedTime = currentTime,
                UpdatedTime = currentTime
            };
            var identityResult = await _roleManager.CreateAsync(role);
            if (!identityResult.Succeeded)
            {
                result.Result = Result.Failed;
                result.Message = string.Join("\n", identityResult.Errors.Select(e => e.Description));
            }
            return result;
        }


        private async Task<BaseResult> UpdateRoleAsync(RoleModel model)
        {
            var result = new BaseResult();
            var role = await _roleManager.FindByIdAsync(model.Id.ToString());
            if (role != null && role.Id > 0)
            {
                role.Name = model.Name;
                role.Description = model.Description;
                role.UpdatedBy = model.UpdatedBy;
                role.UpdatedByUserName = model.UpdatedByUserName;
                role.UpdatedTime = DateTimeHelper.CurrentTime();
                var identityResult = await _roleManager.UpdateAsync(role);
                if (!identityResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = string.Join("\n", identityResult.Errors.Select(e => e.Description));
                }
            }
            else
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy quyền yêu cầu";
            }
            return result;
        }
        private async Task<UserResult> BuildError(IdentityResult identityResult)
        {
            var result = new UserResult();
            result.Result = Result.Failed;
            result.Message = "Cập nhật thất bại";
            if (identityResult.Errors != null && identityResult.Errors.Count() > 0)
            {
                var errors = identityResult.Errors.ToList();
                foreach (var item in errors)
                {
                    result.ErrorList.Add(item.Description);
                }
            }
            return result;
        }
        private async Task<UserResult> UpdateCommonUser(User user, int updatedBy, string updatedByUserName)
        {
            var result = new UserResult();
            user.UpdatedBy = updatedBy;
            user.UpdatedByUserName = updatedByUserName;
            user.UpdatedTime = DateTimeOffset.Now;

            var identityResult = await _userManager.UpdateAsync(user);
            if (!identityResult.Succeeded)
            {
                return await BuildError(identityResult);
            }
            return result;
        }
        #endregion
    }
}
