using Lada.Framework.Data.Domains.Finance;
using Lada.Framework.Data.Domains.Identity;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.DTO.SmartTable;
using Lada.Framework.Infrastructures;
using Lada.Framework.Infrastructures.Helpers;
using Ladaer.BackEnd.Infrastructures.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Finance;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Finance;
using Ladaer.BackEnd.Infrastructures.Services.Identity;
using Microsoft.EntityFrameworkCore;
using static Ladaer.BackEnd.Infrastructures.DTO.Profiles.FinanceMappingExtensions;

namespace Ladaer.BackEnd.Infrastructures.Services.Finance
{
    /// <summary>
    /// Service quản lý tài khoản ngân hàng người dùng
    /// </summary>
    public class UserBankAccountService : IUserBankAccountService
    {
        private readonly IRepository<UserBankAccount> _userBankAccountRepository;
        private readonly IRepository<Bank> _bankRepository;
        private readonly IUserRepository<User> _userRepository;
        private readonly IPermissionService _permissionService;

        public UserBankAccountService(
            IRepository<UserBankAccount> userBankAccountRepository,
            IRepository<Bank> bankRepository,
            IUserRepository<User> userRepository,
            IPermissionService permissionService)
        {
            _userBankAccountRepository = userBankAccountRepository;
            _bankRepository = bankRepository;
            _userRepository = userRepository;
            _permissionService = permissionService;
        }

        /// <summary>
        /// Tìm kiếm tài khoản ngân hàng người dùng
        /// </summary>
        public async Task<SmartTableResult<UserBankAccountItem>> Search(SmartTableParam param)
        {
            IQueryable<UserBankAccount> query = _userBankAccountRepository.Query()
                .Include(x => x.User)
                .Include(x => x.Bank)
                .Include(x => x.Expenses);

            // Lọc theo từ khóa tìm kiếm
            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.AccountNumber.Contains(keyword) ||
                        x.AccountHolderName.ToLower().Contains(keyword) ||
                        (x.Bank != null && x.Bank.BrandName.ToLower().Contains(keyword)) ||
                        (x.Bank != null && x.Bank.BankCode.ToLower().Contains(keyword)) ||
                        (x.User != null && x.User.UserName != null && x.User.UserName.ToLower().Contains(keyword)));
                }

                if (search.UserId != null && search.UserId > 0)
                {
                    int userId = search.UserId;
                    query = query.Where(x => x.UserId == userId);
                }

                if (search.IsDefault != null)
                {
                    bool isDefault = search.IsDefault;
                    query = query.Where(x => x.IsDefault == isDefault);
                }
            }

            // Sắp xếp mặc định
            param.Sort = new Sort() { Predicate = "CreatedTime", Reverse = true };

            // Sử dụng SmartTableExtension để xử lý phân trang
            return await query.ToSmartTableResultAsync(param, userBankAccount => userBankAccount.ToItem());
        }

        /// <summary>
        /// Lấy thông tin chi tiết tài khoản ngân hàng theo ID
        /// </summary>
        public async Task<UserBankAccountModel> GetById(int id)
        {
            var entity = await _userBankAccountRepository.Query()
                .Include(x => x.User)
                .Include(x => x.Bank)
                .FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted);

            if (entity == null)
            {
                return new UserBankAccountModel();
            }

            return entity.ToModel();
        }

        /// <summary>
        /// Tạo mới hoặc cập nhật tài khoản ngân hàng
        /// </summary>
        public async Task<BaseResult> CreateOrUpdate(UserBankAccountModel model)
        {
            var result = new BaseResult();

            try
            {
                // Validation
                if (string.IsNullOrEmpty(model.AccountNumber))
                {
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = "Số tài khoản không được để trống";
                    return result;
                }

                if (string.IsNullOrEmpty(model.AccountHolderName))
                {
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = "Tên chủ tài khoản không được để trống";
                    return result;
                }

                if (model.BankId <= 0)
                {
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = "Ngân hàng không được để trống";
                    return result;
                }

                // Kiểm tra Bank có tồn tại không
                var bank = await _bankRepository.GetByIdAsync(model.BankId);
                if (bank == null)
                {
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = "Ngân hàng không tồn tại";
                    return result;
                }

                // Kiểm tra UserId
                if (model.UserId <= 0)
                {
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = "UserId không hợp lệ";
                    return result;
                }

                // Kiểm tra user có tồn tại không
                var user = await _userRepository.GetByIdAsync(model.UserId);
                if (user == null)
                {
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = "Người dùng không tồn tại";
                    return result;
                }

                UserBankAccount entity;

                if (model.Id > 0)
                {
                    // Cập nhật
                    entity = await _userBankAccountRepository.GetByIdAsync(model.Id);
                    if (entity == null)
                    {
                        result.Result = Lada.Framework.DTO.Result.Failed;
                        result.Message = "Tài khoản ngân hàng không tồn tại";
                        return result;
                    }

                    // Cập nhật thông tin
                    entity.AccountNumber = model.AccountNumber;
                    entity.AccountHolderName = model.AccountHolderName;
                    entity.BankId = model.BankId;
                    entity.Note = model.Note ?? string.Empty;
                    entity.UpdatedTime = DateTimeOffset.Now;
                    entity.UpdatedBy = model.UpdatedBy;
                    entity.UpdatedByUserName = model.UpdatedByUserName;

                    await _userBankAccountRepository.UpdateAsync(entity);
                }
                else
                {
                    // Tạo mới
                    entity = model.ToEntity();
                    entity.CreatedTime = DateTimeOffset.Now;
                    entity.CreatedBy = model.CreatedBy;
                    entity.CreatedByUserName = model.CreatedByUserName;

                    await _userBankAccountRepository.InsertAsync(entity);
                }

                // Xử lý IsDefault
                if (model.IsDefault)
                {
                    // Bỏ IsDefault của các tài khoản khác của cùng user
                    var otherAccounts = await _userBankAccountRepository.Query()
                        .Where(x => x.UserId == model.UserId && x.Id != entity.Id && !x.IsDeleted)
                        .ToListAsync();

                    foreach (var account in otherAccounts)
                    {
                        account.IsDefault = false;
                        account.UpdatedTime = DateTimeOffset.Now;
                        account.UpdatedBy = model.UpdatedBy;
                        account.UpdatedByUserName = model.UpdatedByUserName;
                        await _userBankAccountRepository.UpdateAsync(account);
                    }

                    // Set IsDefault cho tài khoản hiện tại
                    entity.IsDefault = true;
                    entity.UpdatedTime = DateTimeOffset.Now;
                    entity.UpdatedBy = model.UpdatedBy;
                    entity.UpdatedByUserName = model.UpdatedByUserName;
                    await _userBankAccountRepository.UpdateAsync(entity);
                }

                result.Result = Lada.Framework.DTO.Result.Success;
                result.Message = model.Id > 0 ? "Cập nhật tài khoản ngân hàng thành công" : "Tạo mới tài khoản ngân hàng thành công";
            }
            catch (Exception ex)
            {
                result.Result = Lada.Framework.DTO.Result.Failed;
                result.Message = $"Lỗi: {ex.Message}";
            }

            return result;
        }

        /// <summary>
        /// Xóa tài khoản ngân hàng
        /// </summary>
        public async Task<BaseResult> Delete(UserBankAccountModel model)
        {
            var result = new BaseResult();

            try
            {
                if (model.Id <= 0)
                {
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = "ID không hợp lệ";
                    return result;
                }

                var entity = await _userBankAccountRepository.GetByIdAsync(model.Id);
                if (entity == null)
                {
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = "Tài khoản ngân hàng không tồn tại";
                    return result;
                }

                // Soft delete
                entity.IsDeleted = true;
                entity.UpdatedTime = DateTimeOffset.Now;
                entity.UpdatedBy = model.UpdatedBy;
                entity.UpdatedByUserName = model.UpdatedByUserName;

                await _userBankAccountRepository.UpdateAsync(entity);

                result.Result = Lada.Framework.DTO.Result.Success;
                result.Message = "Xóa tài khoản ngân hàng thành công";
            }
            catch (Exception ex)
            {
                result.Result = Lada.Framework.DTO.Result.Failed;
                result.Message = $"Lỗi: {ex.Message}";
            }

            return result;
        }

        /// <summary>
        /// Lấy danh sách tài khoản ngân hàng của người dùng
        /// </summary>
        /// <param name="userId">ID người dùng</param>
        /// <returns>Danh sách tài khoản ngân hàng</returns>
        public async Task<List<UserBankAccountItem>> GetByUserId(int userId)
        {
            var query = _userBankAccountRepository.Query()
                .Include(x => x.User)
                .Include(x => x.Bank)
                .Where(x => x.UserId == userId)
                .OrderByDescending(x => x.IsDefault)
                .ThenByDescending(x => x.CreatedTime);

            var entities = await query.ToListAsync();
            return entities.Select(x => x.ToItem()).ToList();
        }

        /// <summary>
        /// Tìm kiếm tài khoản ngân hàng của người dùng cụ thể
        /// </summary>
        /// <param name="param">Tham số tìm kiếm</param>
        /// <param name="userId">ID người dùng</param>
        /// <returns>Kết quả tìm kiếm</returns>
        public async Task<SmartTableResult<UserBankAccountItem>> SearchByUserId(SmartTableParam param, int userId)
        {
            IQueryable<UserBankAccount> query = _userBankAccountRepository.Query()
                .Include(x => x.User)
                .Include(x => x.Bank)
                .Include(x => x.Expenses)
                .Where(x => x.UserId == userId); // Chỉ lấy tài khoản của user này

            // Lọc theo từ khóa tìm kiếm
            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.AccountNumber.Contains(keyword) ||
                        x.AccountHolderName.ToLower().Contains(keyword) ||
                        (x.Bank != null && x.Bank.BrandName.ToLower().Contains(keyword)) ||
                        (x.Bank != null && x.Bank.BankCode.ToLower().Contains(keyword)));
                }

                if (search.IsDefault != null)
                {
                    bool isDefault = search.IsDefault;
                    query = query.Where(x => x.IsDefault == isDefault);
                }
            }

            // Sắp xếp mặc định
            param.Sort = new Sort() { Predicate = "CreatedTime", Reverse = true };

            // Sử dụng SmartTableExtension để xử lý phân trang
            return await query.ToSmartTableResultAsync(param, entity => entity.ToItem());
        }

        /// <summary>
        /// Lấy tài khoản ngân hàng theo ID và kiểm tra quyền sở hữu
        /// </summary>
        /// <param name="id">ID tài khoản ngân hàng</param>
        /// <param name="userId">ID người dùng</param>
        /// <returns>Thông tin tài khoản ngân hàng</returns>
        public async Task<UserBankAccountModel?> GetByIdAndUserId(int id, int userId)
        {
            var entity = await _userBankAccountRepository.Query()
                .Include(x => x.User)
                .Include(x => x.Bank)
                .FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId);

            return entity?.ToModel();
        }

        /// <summary>
        /// Xóa tài khoản ngân hàng với kiểm tra quyền sở hữu
        /// </summary>
        /// <param name="id">ID tài khoản ngân hàng</param>
        /// <param name="userId">ID người dùng</param>
        /// <param name="updatedBy">ID người cập nhật</param>
        /// <param name="updatedByUserName">Tên người cập nhật</param>
        /// <returns>Kết quả của thao tác</returns>
        public async Task<BaseResult> DeleteByIdAndUserId(int id, int userId, int updatedBy, string updatedByUserName)
        {
            var result = new BaseResult();

            try
            {
                var entity = await _userBankAccountRepository.Query()
                    .FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId);

                if (entity == null)
                {
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = "Không tìm thấy tài khoản ngân hàng hoặc bạn không có quyền xóa";
                    return result;
                }

                // Kiểm tra xem có expense nào đang sử dụng tài khoản này không
                var hasExpenses = await _userBankAccountRepository.Query()
                    .Where(x => x.Id == id)
                    .SelectMany(x => x.Expenses)
                    .AnyAsync(x => !x.IsDeleted);

                if (hasExpenses)
                {
                    result.Result = Lada.Framework.DTO.Result.Failed;
                    result.Message = "Không thể xóa tài khoản đã có chi phí liên kết";
                    return result;
                }

                // Set thông tin người cập nhật
                entity.UpdatedBy = updatedBy;
                entity.UpdatedByUserName = updatedByUserName;
                entity.UpdatedTime = DateTimeOffset.UtcNow;

                await _userBankAccountRepository.DeleteAsync(entity);

                result.Result = Lada.Framework.DTO.Result.Success;
                result.Message = "Xóa tài khoản ngân hàng thành công";
            }
            catch (Exception ex)
            {
                result.Result = Lada.Framework.DTO.Result.Failed;
                result.Message = $"Lỗi: {ex.Message}";
            }

            return result;
        }
    }
}