using Lada.Framework.Data.Domains;
using Lada.Framework.Data.Domains.Crm;
using Lada.Framework.Data.Enums;
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.Profiles;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Crm;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Crm;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Crm;
using Microsoft.EntityFrameworkCore;

namespace Ladaer.BackEnd.Infrastructures.Services.Crm
{
    /// <summary>
    /// Giao diện cho dịch vụ quản lý tài khoản ngân hàng khách hàng.
    /// </summary>
    public interface ICustomerBankAccountService
    {
        /// <summary>
        /// Lấy danh sách tài khoản ngân hàng của khách hàng.
        /// </summary>
        /// <param name="customerId">ID khách hàng.</param>
        /// <returns>Danh sách tài khoản ngân hàng.</returns>
        Task<List<CustomerBankAccountItem>> GetByCustomerId(int customerId);

        /// <summary>
        /// Lấy tài khoản ngân hàng mặc định của khách hàng.
        /// </summary>
        /// <param name="customerId">ID khách hàng.</param>
        /// <returns>Tài khoản ngân hàng mặc định.</returns>
        Task<CustomerBankAccountItem?> GetDefaultByCustomerId(int customerId);

        /// <summary>
        /// Lấy thông tin tài khoản ngân hàng theo ID.
        /// </summary>
        /// <param name="id">ID tài khoản.</param>
        /// <returns>Thông tin tài khoản ngân hàng.</returns>
        Task<CustomerBankAccountModel> GetById(int id);

        /// <summary>
        /// Tạo hoặc cập nhật tài khoản ngân hàng.
        /// </summary>
        /// <param name="model">Thông tin tài khoản ngân hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<CustomerBankAccountResult> CreateOrUpdate(CustomerBankAccountModel model);

        /// <summary>
        /// Xóa tài khoản ngân hàng.
        /// </summary>
        /// <param name="id">ID tài khoản.</param>
        /// <param name="currentUser">Thông tin người dùng hiện tại.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<BaseResult> Delete(int id, CurrentUser currentUser);

        /// <summary>
        /// Đặt tài khoản làm mặc định.
        /// </summary>
        /// <param name="id">ID tài khoản.</param>
        /// <param name="currentUser">Thông tin người dùng hiện tại.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<BaseResult> SetDefault(int id, CurrentUser currentUser);

        /// <summary>
        /// Tìm kiếm tài khoản ngân hàng.
        /// </summary>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <param name="customerId">ID khách hàng (tùy chọn).</param>
        /// <param name="bankCode">Mã ngân hàng (tùy chọn).</param>
        /// <returns>Danh sách tài khoản ngân hàng.</returns>
        Task<List<CustomerBankAccountItem>> Search(string? keyword = null, int? customerId = null, string? bankCode = null);

        /// <summary>
        /// Tìm kiếm tài khoản ngân hàng với SmartTable.
        /// </summary>
        /// <param name="param">Tham số SmartTable.</param>
        /// <returns>Kết quả tìm kiếm dưới dạng SmartTableResult.</returns>
        Task<SmartTableResult<CustomerBankAccountItem>> Search(SmartTableParam param);

        /// <summary>
        /// Gợi ý tài khoản ngân hàng cho khách hàng.
        /// </summary>
        /// <param name="customerId">ID khách hàng.</param>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <returns>Danh sách gợi ý.</returns>
        Task<List<CustomerBankAccountItem>> Suggest(int customerId, string? keyword = null);
    }

    /// <summary>
    /// Dịch vụ quản lý tài khoản ngân hàng khách hàng.
    /// </summary>
    public class CustomerBankAccountService : ICustomerBankAccountService
    {
        private readonly IRepository<CustomerBankAccount> _customerBankAccountRepository;
        private readonly IRepository<Customer> _customerRepository;

        /// <summary>
        /// Khởi tạo dịch vụ quản lý tài khoản ngân hàng khách hàng.
        /// </summary>
        /// <param name="customerBankAccountRepository">Repository tài khoản ngân hàng.</param>
        /// <param name="customerRepository">Repository khách hàng.</param>
        public CustomerBankAccountService(
            IRepository<CustomerBankAccount> customerBankAccountRepository,
            IRepository<Customer> customerRepository)
        {
            _customerBankAccountRepository = customerBankAccountRepository;
            _customerRepository = customerRepository;
        }

        /// <summary>
        /// Lấy danh sách tài khoản ngân hàng của khách hàng.
        /// </summary>
        /// <param name="customerId">ID khách hàng.</param>
        /// <returns>Danh sách tài khoản ngân hàng.</returns>
        public async Task<List<CustomerBankAccountItem>> GetByCustomerId(int customerId)
        {
            var query = _customerBankAccountRepository.Query()
                .Include(x => x.Customer)
                .Where(x => x.CustomerId == customerId)
                .OrderByDescending(x => x.IsDefault)
                .ThenByDescending(x => x.CreatedTime);

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

        /// <summary>
        /// Lấy tài khoản ngân hàng mặc định của khách hàng.
        /// </summary>
        /// <param name="customerId">ID khách hàng.</param>
        /// <returns>Tài khoản ngân hàng mặc định.</returns>
        public async Task<CustomerBankAccountItem?> GetDefaultByCustomerId(int customerId)
        {
            var bankAccount = await _customerBankAccountRepository.Query()
                .Include(x => x.Customer)
                .Where(x => x.CustomerId == customerId && x.IsDefault)
                .FirstOrDefaultAsync();

            return bankAccount?.ToItem();
        }

        /// <summary>
        /// Lấy thông tin tài khoản ngân hàng theo ID.
        /// </summary>
        /// <param name="id">ID tài khoản.</param>
        /// <returns>Thông tin tài khoản ngân hàng.</returns>
        public async Task<CustomerBankAccountModel> GetById(int id)
        {
            var bankAccount = await _customerBankAccountRepository.Query()
                .Include(x => x.Customer)
                .FirstOrDefaultAsync(x => x.Id == id);

            return bankAccount?.ToModel() ?? new CustomerBankAccountModel();
        }

        /// <summary>
        /// Tạo hoặc cập nhật tài khoản ngân hàng.
        /// </summary>
        /// <param name="model">Thông tin tài khoản ngân hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<CustomerBankAccountResult> CreateOrUpdate(CustomerBankAccountModel model)
        {
            var bankAccount = model.ToEntity();

            // Cập nhật thông tin chung của thực thể
            bankAccount = bankAccount.UpdateCommonInt(model.UpdatedBy, model.UpdatedByUsername);

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

        /// <summary>
        /// Xóa tài khoản ngân hàng.
        /// </summary>
        /// <param name="id">ID tài khoản.</param>
        /// <param name="currentUser">Thông tin người dùng hiện tại.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<BaseResult> Delete(int id, CurrentUser currentUser)
        {
            var result = new BaseResult() { Result = Result.Success };
            var bankAccountForDelete = await _customerBankAccountRepository.Query()
                .FirstOrDefaultAsync(x => x.Id == id);

            if (bankAccountForDelete == null)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy tài khoản ngân hàng yêu cầu!";
                return result;
            }

            try
            {
                await _customerBankAccountRepository.DeleteAsync(bankAccountForDelete);
                result.Message = "Xóa tài khoản ngân hàng thành công!";
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = $"Lỗi khi xóa tài khoản ngân hàng: {ex.Message}";
            }

            return result;
        }

        /// <summary>
        /// Đặt tài khoản làm mặc định.
        /// </summary>
        /// <param name="id">ID tài khoản.</param>
        /// <param name="currentUser">Thông tin người dùng hiện tại.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<BaseResult> SetDefault(int id, CurrentUser currentUser)
        {
            var result = new BaseResult() { Result = Result.Success };
            var bankAccount = await _customerBankAccountRepository.Query()
                .FirstOrDefaultAsync(x => x.Id == id);

            if (bankAccount == null)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy tài khoản ngân hàng yêu cầu!";
                return result;
            }

            try
            {
                // Bỏ default của các tài khoản khác cùng khách hàng
                var otherAccounts = await _customerBankAccountRepository.Query()
                    .Where(x => x.CustomerId == bankAccount.CustomerId && x.Id != id && x.IsDefault)
                    .ToListAsync();

                foreach (var account in otherAccounts)
                {
                    account.IsDefault = false;
                    account.UpdateCommonInt(currentUser.UserId, currentUser.UserName);
                    await _customerBankAccountRepository.UpdateAsync(account);
                }

                // Đặt tài khoản hiện tại làm default
                bankAccount.IsDefault = true;
                bankAccount.UpdateCommonInt(currentUser.UserId, currentUser.UserName);
                await _customerBankAccountRepository.UpdateAsync(bankAccount);

                result.Message = "Đặt tài khoản mặc định thành công!";
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = $"Lỗi khi đặt tài khoản mặc định: {ex.Message}";
            }

            return result;
        }

        /// <summary>
        /// Tìm kiếm tài khoản ngân hàng.
        /// </summary>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <param name="customerId">ID khách hàng (tùy chọn).</param>
        /// <param name="bankCode">Mã ngân hàng (tùy chọn).</param>
        /// <returns>Danh sách tài khoản ngân hàng.</returns>
        public async Task<List<CustomerBankAccountItem>> Search(string? keyword = null, int? customerId = null, string? bankCode = null)
        {
            IQueryable<CustomerBankAccount> query = _customerBankAccountRepository.Query()
                .Include(x => x.Customer);

            // Filter by customer
            if (customerId.HasValue && customerId.Value > 0)
            {
                query = query.Where(x => x.CustomerId == customerId.Value);
            }

            // Filter by bank code
            if (!string.IsNullOrWhiteSpace(bankCode))
            {
                query = query.Where(x => x.BankCode.Contains(bankCode));
            }

            // Filter by keyword
            if (!string.IsNullOrWhiteSpace(keyword))
            {
                keyword = keyword.Trim().ToLower();
                query = query.Where(x =>
                    x.AccountNumber.ToLower().Contains(keyword) ||
                    x.AccountHolderName.ToLower().Contains(keyword) ||
                    x.BankName.ToLower().Contains(keyword) ||
                    x.BranchName.ToLower().Contains(keyword) ||
                    (x.Customer != null && x.Customer.FullName.ToLower().Contains(keyword))
                );
            }

            return await query
                .OrderByDescending(x => x.IsDefault)
                .ThenByDescending(x => x.CreatedTime)
                .Take(50)
                .Select(x => x.ToItem())
                .ToListAsync();
        }

        /// <summary>
        /// Tìm kiếm tài khoản ngân hàng với SmartTable.
        /// </summary>
        /// <param name="param">Tham số SmartTable.</param>
        /// <returns>Kết quả tìm kiếm dưới dạng SmartTableResult.</returns>
        public async Task<SmartTableResult<CustomerBankAccountItem>> Search(SmartTableParam param)
        {
            IQueryable<CustomerBankAccount> query = _customerBankAccountRepository.Query()
                .Include(x => x.Customer);

            if (param.Search.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;

                if (search.Keyword != null)
                {
                    string keyword = search.Keyword;
                    keyword = keyword.Trim().ToLower();
                    if (!string.IsNullOrEmpty(keyword))
                    {
                        query = query.Where(x =>
                            x.AccountNumber.ToLower().Contains(keyword) ||
                            x.AccountHolderName.ToLower().Contains(keyword) ||
                            x.BankName.ToLower().Contains(keyword) ||
                            x.BranchName.ToLower().Contains(keyword) ||
                            (x.Customer != null && x.Customer.FullName.ToLower().Contains(keyword))
                        );
                    }
                }

                if (search.CustomerId != null)
                {
                    int customerId = (int)search.CustomerId;
                    if (customerId > 0)
                    {
                        query = query.Where(x => x.CustomerId == customerId);
                    }
                }

                if (search.BankCode != null)
                {
                    string bankCode = search.BankCode;
                    if (!string.IsNullOrWhiteSpace(bankCode))
                    {
                        query = query.Where(x => x.BankCode.Contains(bankCode));
                    }
                }

                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);
                }
            }

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

        /// <summary>
        /// Gợi ý tài khoản ngân hàng cho khách hàng.
        /// </summary>
        /// <param name="customerId">ID khách hàng.</param>
        /// <param name="keyword">Từ khóa tìm kiếm.</param>
        /// <returns>Danh sách gợi ý.</returns>
        public async Task<List<CustomerBankAccountItem>> Suggest(int customerId, string? keyword = null)
        {
            var query = _customerBankAccountRepository.Query()
                .Include(x => x.Customer)
                .Where(x => x.CustomerId == customerId);

            // Filter by keyword
            if (!string.IsNullOrWhiteSpace(keyword))
            {
                keyword = keyword.Trim().ToLower();
                query = query.Where(x =>
                    x.AccountNumber.ToLower().Contains(keyword) ||
                    x.AccountHolderName.ToLower().Contains(keyword) ||
                    x.BankName.ToLower().Contains(keyword) ||
                    x.BranchName.ToLower().Contains(keyword)
                );
            }

            return await query
                .OrderByDescending(x => x.IsDefault)
                .ThenByDescending(x => x.CreatedTime)
                .Take(10)
                .Select(x => x.ToItem())
                .ToListAsync();
        }

        #region Private Methods

        /// <summary>
        /// Tạo tài khoản ngân hàng mới.
        /// </summary>
        /// <param name="bankAccount">Thông tin tài khoản ngân hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        private async Task<CustomerBankAccountResult> Create(CustomerBankAccount bankAccount)
        {
            var result = new CustomerBankAccountResult() { Result = Result.Success };

            // Kiểm tra khách hàng có tồn tại không
            var customer = await _customerRepository.Query()
                .FirstOrDefaultAsync(x => x.Id == bankAccount.CustomerId);
            if (customer == null)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy khách hàng!";
                return result;
            }

            // Kiểm tra trùng lặp số tài khoản
            var existingAccount = await _customerBankAccountRepository.Query()
                .FirstOrDefaultAsync(x => x.CustomerId == bankAccount.CustomerId
                    && x.AccountNumber == bankAccount.AccountNumber
                    && x.BankCode == bankAccount.BankCode);
            if (existingAccount != null)
            {
                result.Result = Result.Failed;
                result.Message = "Số tài khoản này đã tồn tại cho khách hàng!";
                return result;
            }

            try
            {
                // Nếu đây là tài khoản đầu tiên hoặc được đặt làm default
                var accountCount = await _customerBankAccountRepository.Query()
                    .CountAsync(x => x.CustomerId == bankAccount.CustomerId);
                if (accountCount == 0 || bankAccount.IsDefault)
                {
                    // Bỏ default của các tài khoản khác
                    var otherAccounts = await _customerBankAccountRepository.Query()
                        .Where(x => x.CustomerId == bankAccount.CustomerId && x.IsDefault)
                        .ToListAsync();
                    foreach (var account in otherAccounts)
                    {
                        account.IsDefault = false;
                        await _customerBankAccountRepository.UpdateAsync(account);
                    }
                    bankAccount.IsDefault = true;
                }

                await _customerBankAccountRepository.InsertAsync(bankAccount);
                result.Message = "Tạo tài khoản ngân hàng thành công!";
                result.Data = bankAccount.ToItem();
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = $"Lỗi khi tạo tài khoản ngân hàng: {ex.Message}";
            }

            return result;
        }

        /// <summary>
        /// Cập nhật tài khoản ngân hàng.
        /// </summary>
        /// <param name="bankAccount">Thông tin tài khoản ngân hàng.</param>
        /// <returns>Kết quả của thao tác.</returns>
        private async Task<CustomerBankAccountResult> Update(CustomerBankAccount bankAccount)
        {
            var result = new CustomerBankAccountResult() { Result = Result.Success };
            var bankAccountForUpdate = await _customerBankAccountRepository.Query()
                .FirstOrDefaultAsync(x => x.Id == bankAccount.Id);

            if (bankAccountForUpdate == null)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy tài khoản ngân hàng yêu cầu!";
                return result;
            }

            // Kiểm tra trùng lặp số tài khoản (trừ chính nó)
            var existingAccount = await _customerBankAccountRepository.Query()
                .FirstOrDefaultAsync(x => x.CustomerId == bankAccount.CustomerId
                    && x.AccountNumber == bankAccount.AccountNumber
                    && x.BankCode == bankAccount.BankCode
                    && x.Id != bankAccount.Id);
            if (existingAccount != null)
            {
                result.Result = Result.Failed;
                result.Message = "Số tài khoản này đã tồn tại cho khách hàng!";
                return result;
            }

            try
            {
                // Cập nhật thông tin
                bankAccountForUpdate.AccountNumber = bankAccount.AccountNumber;
                bankAccountForUpdate.AccountHolderName = bankAccount.AccountHolderName;
                bankAccountForUpdate.BankCode = bankAccount.BankCode;
                bankAccountForUpdate.BankName = bankAccount.BankName;
                bankAccountForUpdate.BranchName = bankAccount.BranchName;
                bankAccountForUpdate.BranchAddress = bankAccount.BranchAddress;
                bankAccountForUpdate.Note = bankAccount.Note;
                bankAccountForUpdate.UpdatedBy = bankAccount.UpdatedBy;
                bankAccountForUpdate.UpdatedByUserName = bankAccount.UpdatedByUserName;
                bankAccountForUpdate.UpdatedTime = bankAccount.UpdatedTime;

                // Xử lý default
                if (bankAccount.IsDefault && !bankAccountForUpdate.IsDefault)
                {
                    // Bỏ default của các tài khoản khác
                    var otherAccounts = await _customerBankAccountRepository.Query()
                        .Where(x => x.CustomerId == bankAccount.CustomerId && x.Id != bankAccount.Id && x.IsDefault)
                        .ToListAsync();
                    foreach (var account in otherAccounts)
                    {
                        account.IsDefault = false;
                        await _customerBankAccountRepository.UpdateAsync(account);
                    }
                }
                bankAccountForUpdate.IsDefault = bankAccount.IsDefault;

                await _customerBankAccountRepository.UpdateAsync(bankAccountForUpdate);
                result.Message = "Cập nhật tài khoản ngân hàng thành công!";
                result.Data = bankAccountForUpdate.ToItem();
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = $"Lỗi khi cập nhật tài khoản ngân hàng: {ex.Message}";
            }

            return result;
        }

        #endregion
    }
}
