using Lada.Framework.Data.Domains.Categories;
using Lada.Framework.Data.Domains.Identity;
using Lada.Framework.Data.Enums;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.DTO.SmartTable;
using Lada.Framework.Infrastructures.Helpers;
using Ladaer.BackEnd.Infrastructures.AppSettings;
using Ladaer.BackEnd.Infrastructures.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Categories;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Identity;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Accounts;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Users;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Accounts;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Users;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using System.Data;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;

namespace Ladaer.BackEnd.Infrastructures.Services.Identity
{
    /// <summary>
    /// Giao diện cho dịch vụ quản lý người dùng.
    /// </summary>
    public interface IUserService
    {
        /// <summary>
        /// Gợi ý người dùng dựa trên từ khóa và loại người dùng.
        /// </summary>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <param name="userType">Loại người dùng.</param>
        /// <param name="roleName">Tên vai trò (tùy chọn).</param>
        /// <returns>Danh sách người dùng gợi ý.</returns>
        Task<List<UserOptionItem>> SugUser(string keyword, UserType userType, string roleName = "");

        /// <summary>
        /// Tự động hoàn thành tìm kiếm người dùng dựa trên từ khóa và loại người dùng.
        /// </summary>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <param name="userType">Loại người dùng.</param>
        /// <returns>Danh sách người dùng gợi ý.</returns>
        Task<List<UserOptionItem>> AutoComplete(string keyword, UserType userType);

        /// <summary>
        /// Tự động hoàn thành tìm kiếm người dùng dựa trên từ khóa và ID đại lý.
        /// </summary>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <param name="agencyId">ID của đại lý.</param>
        /// <returns>Danh sách người dùng gợi ý.</returns>
        Task<List<UserOptionItem>> AutoCompleteByAgency(string keyword, int agencyId);

        /// <summary>
        /// Lấy thông tin nhân viên theo ID.
        /// </summary>
        /// <param name="id">ID của nhân viên.</param>
        /// <returns>Thông tin nhân viên.</returns>
        Task<StaffItem> GetByIdAsync(int id);

        Task<StaffModel> GetStaffModelByIdAsync(int id);

        /// <summary>
        /// Lấy danh sách thông tin nhân viên theo danh sách ID.
        /// </summary>
        /// <param name="ids">Danh sách ID của nhân viên.</param>
        /// <returns>Danh sách thông tin nhân viên.</returns>
        Task<List<StaffItem>> GetByListIdAsync(List<int> ids);

        /// <summary>
        /// Lấy ID của đại lý theo ID của nhân viên.
        /// </summary>
        /// <param name="id">ID của nhân viên.</param>
        /// <returns>ID của đại lý.</returns>
        Task<int> GetAgencyIdByIdAsync(int id);

        /// <summary>
        /// Lấy danh sách quyền của người dùng
        /// </summary>
        /// <param name="id">ID của nhân viên.</param>
        /// <returns>Danh sách quyền.</returns>
        Task<List<string>> GetRolesAsync(int id);

        /// <summary>
        /// Lấy thông tin người dùng cần đăng nhập
        /// </summary>
        /// <param name="userKeyword"></param>
        /// <returns></returns>
        Task<User?> GetUserLogin(string userKeyword);

        Task<LoginResult> RefreshToken(string refreshToken, string deviceId);

        Task<LoginResult> Login(LoginModel model);

        Task<SmartTableResult<StaffItem>> Search(SmartTableParam param, UserType userType);

        Task<UserResult> UpdateStaff(StaffModel model);
        Task<UserResult> DeleteStaff(int id, int updatedBy, string updatedByUserName);
        Task<RegisterResult> RegisterStaff([FromBody] RegisterModel model);
        Task<UserResult> Lock(UserStatusModel model);
        Task<UserResult> UnLock(UserStatusModel model);

        /// <summary>
        /// Đổi mật khẩu cho người dùng
        /// </summary>
        /// <param name="model">Thông tin đổi mật khẩu</param>
        /// <returns>Kết quả đổi mật khẩu</returns>
        Task<UserResult> ChangePassword(ChangePasswordModel model);

        Task<UserResult> SetPassword(SetPasswordModel model);

        Task<List<StaffItem>> GetByPermissionAsync(int permissionId);

    }
    /// <summary>
    /// Triển khai dịch vụ quản lý người dùng.
    /// </summary>
    public class UserService : IUserService
    {
        private readonly IUserRepository<User> _userRepository;
        private readonly IRepository<RefreshToken> _refreshTokenRepository;
        private readonly UserManager<User> _userManager;
        private readonly IRepository<Agency> _agencyRepository;
        private readonly IRepository<Permission> _permissionRepository;
        IConfiguration _configuration;

        /// <summary>
        /// Khởi tạo một thể hiện của <see cref="UserService"/>.
        /// </summary>
        /// <param name="userRepository">Đối tượng IUserRepository của User.</param>
        public UserService(IConfiguration configuration,
                IUserRepository<User> userRepository,
                UserManager<User> userManager, IRepository<RefreshToken> refreshTokenRepository, IRepository<Agency> agencyRepository, IRepository<Permission> permissionRepository)
        {
            _userRepository = userRepository;
            _userManager = userManager;
            _refreshTokenRepository = refreshTokenRepository;
            _configuration = configuration;
            _agencyRepository = agencyRepository;
            _permissionRepository = permissionRepository;
        }

        /// <summary>
        /// Gợi ý người dùng dựa trên từ khóa và loại người dùng.
        /// </summary>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <param name="userType">Loại người dùng.</param>
        /// <param name="roleName">Tên vai trò (tùy chọn).</param>
        /// <returns>Danh sách người dùng gợi ý.</returns>
        public async Task<List<UserOptionItem>> SugUser(string keyword, UserType userType, string roleName = "")
        {
            var result = new List<UserOptionItem>();
            var query = _userRepository.Query().Where(u => u.UserType == userType);
            // Chỉ lấy ra các tài khoản còn hoạt động
            query = query.Where(u => !u.LockoutEnabled || (u.LockoutEnabled && (u.LockoutEnd == null || u.LockoutEnd <= DateTimeHelper.CurrentTime())));
            if (!string.IsNullOrEmpty(keyword))
            {
                keyword = keyword.Trim().ToLower();
                query = query.Where(x => (!string.IsNullOrEmpty(x.UserName) && x.UserName.ToLower().Contains(keyword))
                                || x.FullName.ToLower().Contains(keyword));
            }
            if (!string.IsNullOrEmpty(roleName))
            {
                //query = query.Where(u => u.UserRoles.Any(ur => ur.Role.Name == roleName));
                query = query.Where(u => u.Permission!=null && u.Permission.PermissionRoles.Any(pr=>pr.Role.Name == roleName));
            }

            result = await query.Take(25).OrderByDescending(u => u.CreatedTime).Select(u => u.ToOptionItem()).ToListAsync();
            return result;
        }

        /// <summary>
        /// Tự động hoàn thành tìm kiếm người dùng dựa trên từ khóa và loại người dùng.
        /// </summary>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <param name="userType">Loại người dùng.</param>
        /// <returns>Danh sách người dùng gợi ý.</returns>
        public async Task<List<UserOptionItem>> AutoComplete(string keyword, UserType userType)
        {
            var result = new List<UserOptionItem>();
            var query = _userRepository.Query().Where(u => u.UserType == userType);
            // Chỉ lấy ra các tài khoản còn hoạt động
            query = query.Where(u => !u.LockoutEnabled || (u.LockoutEnabled && (u.LockoutEnd == null || u.LockoutEnd <= DateTimeHelper.CurrentTime())));
            if (!string.IsNullOrEmpty(keyword))
            {
                keyword = keyword.Trim().ToLower();
                query = query.Where(x => x.UserName.ToLower().Contains(keyword)
                                || x.FullName.ToLower().Contains(keyword));
            }

            result = await query.Take(10).OrderByDescending(u => u.CreatedTime).Select(u => u.ToOptionItem()).ToListAsync();
            return result;
        }

        /// <summary>
        /// Tự động hoàn thành tìm kiếm người dùng dựa trên từ khóa và ID đại lý.
        /// </summary>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <param name="agencyId">ID của đại lý.</param>
        /// <returns>Danh sách người dùng gợi ý.</returns>
        public async Task<List<UserOptionItem>> AutoCompleteByAgency(string keyword, int agencyId)
        {
            var result = new List<UserOptionItem>();
            if (agencyId > 0)
            {
                var query = _userRepository.Query().Where(u => u.AgencyId == agencyId);
                // Chỉ lấy ra các tài khoản còn hoạt động
                query = query.Where(u => !u.LockoutEnabled || (u.LockoutEnabled && (u.LockoutEnd == null || u.LockoutEnd <= DateTimeHelper.CurrentTime())));
                if (!string.IsNullOrEmpty(keyword))
                {
                    keyword = keyword.Trim().ToLower();
                    query = query.Where(x => x.UserName.ToLower().Contains(keyword)
                                    || x.FullName.ToLower().Contains(keyword));
                }

                result = await query.OrderByDescending(u => u.CreatedTime).Take(10).Select(u => u.ToOptionItem()).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// Lấy thông tin nhân viên theo ID.
        /// </summary>
        /// <param name="id">ID của nhân viên.</param>
        /// <returns>Thông tin nhân viên.</returns>
        public async Task<StaffItem> GetByIdAsync(int id)
        {
            var result = new StaffItem();
            var user = await _userRepository.Query().FirstOrDefaultAsync(u => u.Id == id);

            if (user != null && user.Id > 0)
            {
                result = user.ToStaffItem();
                result.IsLocked = user.LockoutEnabled && (user.LockoutEnd != null && user.LockoutEnd > DateTimeHelper.CurrentTime());
            }
            return result;
        }

        public async Task<StaffModel> GetStaffModelByIdAsync(int id)
        {
            var result = new StaffModel();
            var user = await _userRepository.Query().FirstOrDefaultAsync(u => u.Id == id);

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

        /// <summary>
        /// Lấy danh sách thông tin nhân viên theo danh sách ID.
        /// </summary>
        /// <param name="ids">Danh sách ID của nhân viên.</param>
        /// <returns>Danh sách thông tin nhân viên.</returns>
        public async Task<List<StaffItem>> GetByListIdAsync(List<int> ids)
        {
            var result = new List<StaffItem>();
            var users = await _userRepository.Query().Where(u => ids.Contains(u.Id)).ToListAsync();
            if (users != null && users.Any())
            {
                foreach (var user in users)
                {
                    var staffItem = user.ToStaffItem();
                    staffItem.IsLocked = user.LockoutEnabled && (user.LockoutEnd != null && user.LockoutEnd > DateTimeHelper.CurrentTime());
                    result.Add(staffItem);
                }
            }
            return result;
        }

        /// <summary>
        /// Lấy ID của đại lý theo ID của nhân viên.
        /// </summary>
        /// <param name="id">ID của nhân viên.</param>
        /// <returns>ID của đại lý.</returns>
        public async Task<int> GetAgencyIdByIdAsync(int id)
        {
            var user = await _userRepository.Query().FirstOrDefaultAsync(u => u.Id == id);
            return user != null && user.Id > 0 ? user.AgencyId.HasValue ? user.AgencyId.Value : 0 : 0;
        }

        /// <summary>
        /// Lấy danh sách quyền của người dùng từ cả UserRole và PermissionRole
        /// </summary>
        /// <param name="id">ID của nhân viên.</param>
        /// <returns>Danh sách quyền.</returns>
        public async Task<List<string>> GetRolesAsync(int id)
        {
            var user = await _userRepository.Query()
                .Include(u => u.UserRoles)
                    .ThenInclude(ur => ur.Role)
                .Include(u => u.Permission!)
                    .ThenInclude(p => p.PermissionRoles)
                        .ThenInclude(pr => pr.Role)
                .FirstOrDefaultAsync(u => u.Id == id);

            if (user == null || user.Id <= 0)
            {
                return new List<string>();
            }

            return GetAllUserRoles(user);
        }

        public async Task<User?> GetUserLogin(string userKeyword)
        {
            userKeyword = userKeyword.Trim().ToUpper();
            return await _userRepository.Query()
                        .FirstOrDefaultAsync(u =>
                                                (!string.IsNullOrEmpty(u.UserName) && u.UserName.ToUpper() == userKeyword)
                                                || (!string.IsNullOrEmpty(u.PhoneNumber) && u.PhoneNumber == userKeyword)
                                                || (!string.IsNullOrEmpty(u.Email) && u.Email.ToUpper() == userKeyword));
        }

        public async Task<LoginResult> Login(LoginModel model)
        {
            var token = string.Empty;
            var result = new LoginResult();
            var userKeyword = model.UserName.Trim().ToUpper();
            var user = await _userRepository.Query()
                        .FirstOrDefaultAsync(u =>
                                                (!string.IsNullOrEmpty(u.UserName) && u.UserName.ToUpper() == userKeyword)
                                                || (!string.IsNullOrEmpty(u.PhoneNumber) && u.PhoneNumber == userKeyword)
                                                || (!string.IsNullOrEmpty(u.Email) && u.Email.ToUpper() == userKeyword));
            if (user == null)
            {
                result.Result = Result.Failed;
                result.Message = "Thông tin đăng nhập không chính xác.";
                return result;
            }

            if (await _userManager.IsLockedOutAsync(user))
            {
                result.Result = Result.Failed;
                result.Message = "Tài khoản đã bị khóa";
                return result;
            }

            if (!await _userManager.CheckPasswordAsync(user, model.Password))
            {
                await _userManager.AccessFailedAsync(user);
                if (await _userManager.IsLockedOutAsync(user))
                {
                    result.Result = Result.Failed;
                    result.Message = "Bạn đã nhập sai quá nhiều lần. Tài khoản tạm thời bị khóa.";
                    return result;
                }

                result.Result = Result.Failed;
                result.Message = "Thông tin đăng nhập không chính xác.";
                return result;
            }

            await _userManager.ResetAccessFailedCountAsync(user);


            result = await GenerateLoginResult(user);

            var refreshToken = GenerateRefreshToken();



            var storedToken = await _refreshTokenRepository.Query().FirstOrDefaultAsync(t => t.UserId == user.Id && t.DeviceId == model.DeviceId);

            if (storedToken == null)
            {
                storedToken = new RefreshToken()
                {
                    Token = refreshToken,
                    DeviceId = model.DeviceId,
                    DeviceInfo = model.DeviceInfo,
                    ExpiryDate = result.ExpiredTime,
                    UserId = user.Id,
                    CreatedBy = user.Id,
                    UpdatedBy = user.Id,
                    CreatedByUserName = user.UserName ?? "",
                    UpdatedByUserName = user.UserName ?? "",
                    CreatedTime = DateTimeHelper.CurrentTime(),
                    UpdatedTime = DateTimeHelper.CurrentTime()
                };
                await _refreshTokenRepository.InsertAsync(storedToken);
            }
            else
            {
                storedToken.Token = refreshToken;
                storedToken.ExpiryDate = result.ExpiredTime;
                storedToken.UpdatedTime = DateTimeHelper.CurrentTime();
                await _refreshTokenRepository.UpdateAsync(storedToken);
            }

            result.RefreshToken = refreshToken;
            return result;

        }

        public async Task<LoginResult> RefreshToken(string refreshToken, string deviceId)
        {
            var result = new LoginResult();
            var storedToken = await _refreshTokenRepository.Query().FirstOrDefaultAsync(t => t.Token == refreshToken && t.DeviceId == deviceId);

            if (storedToken == null || storedToken.ExpiryDate < DateTimeHelper.CurrentTime())
            {
                result.Result = Result.Failed;
                result.Message = "Yêu cầu không hợp lệ";
                return result;
            }

            var user = await _userManager.FindByIdAsync(storedToken.UserId.ToString());
            if (user == null)
            {
                result.Result = Result.Failed;
                result.Message = "Thông tin người dùng không chính xác.";
                return result;
            }

            if (await _userManager.IsLockedOutAsync(user))
            {
                result.Result = Result.Failed;
                result.Message = "Tài khoản đã bị khóa";
                return result;
            }
            result = await GenerateLoginResult(user);


            var newRefreshToken = GenerateRefreshToken();
            storedToken.Token = newRefreshToken;
            storedToken.ExpiryDate = result.ExpiredTime;
            storedToken.UpdatedTime = DateTimeHelper.CurrentTime();
            await _refreshTokenRepository.UpdateAsync(storedToken);

            result.RefreshToken = newRefreshToken;
            return result;
        }


        public async Task<SmartTableResult<StaffItem>> Search(SmartTableParam param, UserType userType)
        {
            var query = _userRepository.Query();
            if (userType == UserType.Staff)
            {
                query = query.Where(u => u.UserType == UserType.Staff || u.UserType == UserType.Franchisee);
                query = query.Include(q => q.Permission);
            }
            else
            {
                query = query.Where(u => u.UserType == userType);
            }
            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.UserName) && x.UserName.ToLower().Contains(keyword)) ||
                                        (!string.IsNullOrEmpty(x.FullName) && x.FullName.ToLower().Contains(keyword)) ||
                                        (!string.IsNullOrEmpty(x.Email) && x.Email.ToLower().Contains(keyword)) ||
                                        (!string.IsNullOrEmpty(x.Address) && x.Address.ToLower().Contains(keyword)) ||
                                        (!string.IsNullOrEmpty(x.PhoneNumber) && x.PhoneNumber.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));
                }
                if (search.IsLocked != null)
                {
                    bool isLocked = search.IsLocked;
                    if (isLocked)
                    {
                        query = query.Where(x => x.LockoutEnabled && x.LockoutEnd.HasValue && x.LockoutEnd.Value > DateTimeOffset.Now);
                    }
                    else
                    {
                        query = query.Where(x => !x.LockoutEnabled || !x.LockoutEnd.HasValue || x.LockoutEnd.Value <= DateTimeOffset.Now);
                    }
                }
                if (search.AgencyId != null)
                {
                    int agencyId = search.AgencyId;
                    if (agencyId > 0)
                    {
                        query = query.Where(x => x.AgencyId == agencyId);
                    }

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

            if (gridData.Items.Any())
            {
                var agencyIds = gridData.Items.Where(u => u.AgencyId > 0).Select(u => u.AgencyId).ToList();
                if (agencyIds.Any())
                {
                    var agencies = _agencyRepository.Query().Where(a => agencyIds.Contains(a.Id)).ToList();
                    if (agencies.Any())
                    {
                        foreach (var item in gridData.Items)
                        {
                            if (item.AgencyId > 0)
                            {
                                var agency = agencies.FirstOrDefault(a => a.Id == item.AgencyId);
                                if (agency != null && agency.Id > 0)
                                {
                                    item.AgencyName = agency.Name;
                                }
                                else
                                {
                                    item.AgencyName = "Phòng ban không tồn tại";
                                }
                            }
                            else
                            {
                                item.AgencyName = "Tự do";
                            }

                        }
                    }
                }
            }

            return gridData;
        }


        public async Task<UserResult> UpdateStaff(StaffModel model)
        {
            var result = new UserResult();
            var phoneDupUser = await _userRepository.Query().FirstOrDefaultAsync(u => u.PhoneNumber == model.PhoneNumber && u.Id != model.Id);
            if (phoneDupUser != null && phoneDupUser.Id > 0)
            {
                result.Result = Result.Failed;
                result.Message = "Số điện thoại đã được đăng ký, vui lòng chọn số điện thoại khác";
                return result;
            }
            var user = await _userRepository.Query().FirstOrDefaultAsync(u => u.Id == model.Id);

            if (user != null && user.Id > 0)
            {
                user.FullName = model.FullName;
                user.Address = model.Address;
                user.PhoneNumber = model.PhoneNumber;
                user.UserName = model.UserName;
                user.Email = model.Email;
                user.UpdatedBy = model.UpdatedBy;
                user.UpdatedByUserName = model.UpdatedByUserName;
                user.UpdatedTime = DateTimeOffset.Now;
                user.AgencyId = model.AgencyId;
                user.FinalDN = model.FinalDN ?? "";
                try
                {
                    await _userRepository.UpdateAsync(user);
                }
                catch (Exception ex)
                {
                    result.Result = Result.Failed;
                    result.Message = "Cập nhật thất bại: " + ex.StackTrace;
                }

            }

            return result;
        }

        public async Task<UserResult> DeleteStaff(int id, int updatedBy, string updatedByUserName)
        {
            var result = new UserResult();

            var user = await _userRepository.Query().FirstOrDefaultAsync(u => u.Id == id);

            if (user != null && user.Id > 0)
            {
                user.IsDeleted = true;
                user.LockoutEnabled = true;
                user.LockoutEnd = DateTimeOffset.Now.AddYears(20);
                user.UpdatedBy = updatedBy;
                user.UpdatedByUserName = updatedByUserName;
                user.UpdatedTime = DateTimeOffset.Now;

                try
                {
                    await _userRepository.UpdateAsync(user);
                }
                catch (Exception ex)
                {
                    result.Result = Result.Failed;
                    result.Message = "Cập nhật thất bại: " + ex.StackTrace;
                }

            }
            return result;
        }

        public async Task<UserResult> Lock(UserStatusModel model)
        {
            var result = new UserResult();

            var user = await _userManager.FindByIdAsync(model.Id.ToString());

            if (user != null && user.Id > 0)
            {
                var identityResult = await _userManager.SetLockoutEnabledAsync(user, true);
                if (!identityResult.Succeeded)
                {
                    return await BuildError(identityResult);
                }

                identityResult = await _userManager.SetLockoutEndDateAsync(user, DateTimeOffset.Now.AddYears(20));
                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;
            }

        }
        public async Task<UserResult> UnLock(UserStatusModel model)
        {
            var result = new UserResult();

            var user = await _userManager.FindByIdAsync(model.Id.ToString());

            if (user != null && user.Id > 0)
            {
                var identityResult = await _userManager.SetLockoutEnabledAsync(user, false);
                if (!identityResult.Succeeded)
                {
                    return await BuildError(identityResult);
                }

                identityResult = await _userManager.SetLockoutEndDateAsync(user, DateTimeOffset.Now.AddYears(20));
                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;
            }

        }

        public async Task<RegisterResult> RegisterStaff([FromBody] RegisterModel model)
        {
            RegisterResult result = new RegisterResult();

            if (model.AgencyId > 0)
            {
                var agency = await _agencyRepository.Query().FirstOrDefaultAsync(a => a.Id == model.AgencyId);
                if (agency == null || agency.Id <= 0 || agency.Status != AgencyStatus.Active)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy chi nhánh hoặc chi nhánh chưa được kích hoạt";
                    return result;
                }
                var userType = agency.AgencyType == AgencyType.Franchise ? UserType.Franchisee : UserType.Staff;
                result = await Register(model, userType);
                return result;

            }
            else
            {
                result.Result = Result.Failed;
                result.Message = "Không có thông tin chi nhánh";
                return result;
            }

        }

        /// <summary>
        /// Đổi mật khẩu cho người dùng
        /// </summary>
        /// <param name="model">Thông tin đổi mật khẩu</param>
        /// <returns>Kết quả đổi mật khẩu</returns>
        public async Task<UserResult> ChangePassword(ChangePasswordModel model)
        {
            var result = new UserResult();

            try
            {
                // Tìm người dùng theo ID
                var user = await _userManager.FindByIdAsync(model.UserId.ToString());
                if (user == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy người dùng";
                    return result;
                }

                // Kiểm tra tài khoản có bị khóa không
                if (await _userManager.IsLockedOutAsync(user))
                {
                    result.Result = Result.Failed;
                    result.Message = "Tài khoản đã bị khóa";
                    return result;
                }

                // Kiểm tra mật khẩu hiện tại
                var isCurrentPasswordValid = await _userManager.CheckPasswordAsync(user, model.CurrentPassword);
                if (!isCurrentPasswordValid)
                {
                    result.Result = Result.Failed;
                    result.Message = "Mật khẩu hiện tại không chính xác";
                    return result;
                }

                // Đổi mật khẩu
                var changePasswordResult = await _userManager.ChangePasswordAsync(user, model.CurrentPassword, model.NewPassword);
                if (!changePasswordResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = "Đổi mật khẩu thất bại";
                    if (changePasswordResult.Errors != null && changePasswordResult.Errors.Any())
                    {
                        foreach (var error in changePasswordResult.Errors)
                        {
                            result.ErrorList.Add(error.Description);
                        }
                    }
                    return result;
                }

                // Cập nhật thông tin người dùng
                user.Password = model.NewPassword;
                user.UpdatedBy = model.UpdatedBy;
                user.UpdatedByUserName = model.UpdatedByUserName;
                user.UpdatedTime = DateTimeOffset.Now;

                var updateResult = await _userManager.UpdateAsync(user);
                if (!updateResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = "Cập nhật thông tin người dùng thất bại";
                    if (updateResult.Errors != null && updateResult.Errors.Any())
                    {
                        foreach (var error in updateResult.Errors)
                        {
                            result.ErrorList.Add(error.Description);
                        }
                    }
                    return result;
                }

                result.Result = Result.Success;
                result.Message = "Đổi mật khẩu thành công";
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = "Lỗi hệ thống: " + ex.Message;
            }

            return result;
        }



        /// <summary>
        /// Đổi mật khẩu cho người dùng
        /// </summary>
        /// <param name="model">Thông tin đổi mật khẩu</param>
        /// <returns>Kết quả đổi mật khẩu</returns>
        public async Task<UserResult> SetPassword(SetPasswordModel model)
        {
            var result = new UserResult();

            try
            {
                // Tìm người dùng theo ID
                var user = await _userManager.FindByIdAsync(model.Id.ToString());
                if (user == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy người dùng";
                    return result;
                }

                // Kiểm tra tài khoản có bị khóa không
                if (await _userManager.IsLockedOutAsync(user))
                {
                    result.Result = Result.Failed;
                    result.Message = "Tài khoản đã bị khóa";
                    return result;
                }


                // Đổi mật khẩu
                var changePasswordResult = await _userManager.ChangePasswordAsync(user, user.Password, model.Password);
                if (!changePasswordResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = "Đổi mật khẩu thất bại";
                    if (changePasswordResult.Errors != null && changePasswordResult.Errors.Any())
                    {
                        foreach (var error in changePasswordResult.Errors)
                        {
                            result.ErrorList.Add(error.Description);
                        }
                    }
                    return result;
                }

                // Cập nhật thông tin người dùng
                user.Password = model.Password;
                user.UpdatedBy = model.UpdatedBy;
                user.UpdatedByUserName = model.UpdatedByUserName;
                user.UpdatedTime = DateTimeOffset.Now;

                var updateResult = await _userManager.UpdateAsync(user);
                if (!updateResult.Succeeded)
                {
                    result.Result = Result.Failed;
                    result.Message = "Cập nhật thông tin người dùng thất bại";
                    if (updateResult.Errors != null && updateResult.Errors.Any())
                    {
                        foreach (var error in updateResult.Errors)
                        {
                            result.ErrorList.Add(error.Description);
                        }
                    }
                    return result;
                }

                result.Result = Result.Success;
                result.Message = "Đổi mật khẩu thành công";
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = "Lỗi hệ thống: " + ex.Message;
            }

            return result;
        }


        public async Task<List<StaffItem>> GetByPermissionAsync(int permissionId)
        {
            if (permissionId <= 0) return new List<StaffItem>();
            return await _userRepository.Query().Where(u =>
                                                        (u.UserType == UserType.Staff || u.UserType == UserType.Franchisee)
                                                        && u.PermissionId != null && u.PermissionId == permissionId)
                                                .Select(u => u.ToStaffItem()).ToListAsync();
        }

        #region Utilities

        /// <summary>
        /// Lấy tất cả roles của user từ cả UserRole và PermissionRole
        /// </summary>
        /// <param name="user">User entity với UserRoles và Permission.PermissionRoles đã được Include</param>
        /// <returns>Danh sách role names (không trùng lặp)</returns>
        private List<string> GetAllUserRoles(User user)
        {
            var roleNames = new HashSet<string>();

            // 1. Lấy roles trực tiếp từ UserRole
            if (user.UserRoles != null && user.UserRoles.Any())
            {
                foreach (var userRole in user.UserRoles)
                {
                    if (userRole.Role != null && !string.IsNullOrEmpty(userRole.Role.Name))
                    {
                        roleNames.Add(userRole.Role.Name);
                    }
                }
            }

            // 2. Lấy roles từ Permission thông qua PermissionRole
            if (user.Permission != null &&
                user.Permission.IsActive &&
                user.Permission.PermissionRoles != null &&
                user.Permission.PermissionRoles.Any())
            {
                foreach (var permissionRole in user.Permission.PermissionRoles)
                {
                    if (permissionRole.Role != null && !string.IsNullOrEmpty(permissionRole.Role.Name))
                    {
                        roleNames.Add(permissionRole.Role.Name);
                    }
                }
            }

            return roleNames.ToList();
        }

        private string GenerateRefreshToken()
        {
            return Convert.ToBase64String(RandomNumberGenerator.GetBytes(32));
        }


        private async Task<LoginResult> GenerateLoginResult(User user)
        {
            //var jwtSettings = _configuration.GetSection("JwtSettings");
            //var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["Secret"]));
            var result = new LoginResult();

            var jwtSettings = _configuration.GetSection("JwtSettings").Get<JwtSettings>();
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.Secret));

            // Lấy user với đầy đủ UserRoles và Permission.PermissionRoles
            var userWithRoles = await _userRepository.Query()
                .Include(u => u.UserRoles)
                    .ThenInclude(ur => ur.Role)
                .Include(u => u.Permission!)
                    .ThenInclude(p => p.PermissionRoles)
                        .ThenInclude(pr => pr.Role)
                .FirstOrDefaultAsync(u => u.Id == user.Id);

            // Lấy tất cả roles từ cả UserRole và PermissionRole
            var roles = userWithRoles != null
                ? GetAllUserRoles(userWithRoles)
                : new List<string>();

            var roleStr = string.Join(",", roles);

            var claims = new List<Claim>
            {
                new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
                new Claim(JwtRegisteredClaimNames.Email, user.Email),
                new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                new Claim(JwtRegisteredClaimNames.PhoneNumber, user.PhoneNumber),
                new Claim(JwtRegisteredClaimNames.GivenName, user.FullName)
            };
            foreach (var role in roles)
            {
                claims.Add(new Claim(ClaimTypes.Role, role));
            }
            var token = new JwtSecurityToken(
                issuer: jwtSettings.Issuer,
                audience: jwtSettings.Audience,
                claims: claims,
                expires: DateTime.UtcNow.AddMinutes(jwtSettings.ExpiryMinutes),
                signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
            );

            result.Email = user.Email;
            result.FullName = user.FullName;
            result.Id = user.Id;
            result.PhoneNumber = user.PhoneNumber;
            result.Roles = roleStr;
            result.UserName = user.UserName;
            result.Token = new JwtSecurityTokenHandler().WriteToken(token);
            result.ExpiredTime = DateTime.UtcNow.AddMinutes(jwtSettings.ExpiryMinutes);
            result.ExpiredTimestamp = result.ExpiredTime.ToUnixTimeSeconds();

            // Lấy Permission name từ userWithRoles (đã Include)
            if (userWithRoles?.Permission != null && userWithRoles.Permission.Id > 0)
            {
                result.Permission = userWithRoles.Permission.Name;
            }
            else
            {
                result.Permission = string.Empty;
            }
            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<RegisterResult> Register(RegisterModel model, UserType userType)
        {
            RegisterResult result = new RegisterResult();
            var currentTime = DateTimeHelper.CurrentTime();
            var phoneDupUser = await _userManager.Users.FirstOrDefaultAsync(u => u.PhoneNumber == model.PhoneNumber);
            if (phoneDupUser != null && phoneDupUser.Id > 0)
            {
                result.Result = Result.Failed;
                result.Message = "Số điện thoại đã được đăng ký, vui lòng chọn số điện thoại khác";
                return result;
            }


            var user = new User
            {
                UserName = model.UserName,
                FullName = model.FullName,
                Email = model.Email,
                PhoneNumber = model.PhoneNumber,
                Address = model.Address,
                Password = model.Password,
                UserType = userType,
                CreatedTime = currentTime,
                UpdatedTime = currentTime,
                AgencyId = model.AgencyId
            };

            if (userType == UserType.Staff || userType == UserType.Franchisee)
            {
                user.CreatedBy = model.UpdatedBy;
                user.CreatedByUserName = model.UpdatedByUserName;
                user.UpdatedBy = model.UpdatedBy;
                user.UpdatedByUserName = model.UpdatedByUserName;
            }

            var createResult = await _userManager.CreateAsync(user, model.Password);

            if (createResult.Succeeded)
            {

                return result;
            }
            else
            {
                result.Result = Result.Failed;
                result.Message = "Đăng ký không thành công";
                if (createResult.Errors.Any())
                {
                    foreach (var item in createResult.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
    }
}
