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.Items.Finance;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Finance;
using Ladaer.BackEnd.Infrastructures.DTO.Profiles;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Finance;
using Microsoft.EntityFrameworkCore;
using static Ladaer.BackEnd.Infrastructures.DTO.Profiles.FinanceMappingExtensions;

namespace Ladaer.BackEnd.Infrastructures.Services.Finance
{
    /// <summary>
    /// Interface cho service quản lý danh mục chi phí
    /// </summary>
    public interface IExpenseCategoryService
    {
        /// <summary>
        /// Tìm kiếm danh mục chi phí với phân trang
        /// </summary>
        Task<SmartTableResult<ExpenseCategoryItem>> Search(SmartTableParam param);

        /// <summary>
        /// Lấy danh mục chi phí theo ID
        /// </summary>
        Task<ExpenseCategoryItem?> GetByIdAsync(int id);

        /// <summary>
        /// Tạo hoặc cập nhật danh mục chi phí
        /// </summary>
        Task<BaseResult> CreateOrUpdateAsync(ExpenseCategoryModel model, CurrentUser currentUser);

        /// <summary>
        /// Xóa danh mục chi phí
        /// </summary>
        Task<BaseResult> DeleteAsync(int id, CurrentUser currentUser);

        /// <summary>
        /// Lấy danh sách tất cả danh mục chi phí (cho dropdown)
        /// </summary>
        Task<List<ExpenseCategoryItem>> GetAllAsync();

        /// <summary>
        /// Kiểm tra tên danh mục có trùng không
        /// </summary>
        Task<bool> IsNameExistsAsync(string name, int excludeId = 0);

        /// <summary>
        /// Lấy danh sách danh mục chi phí theo cây phân cấp
        /// </summary>
        Task<List<ExpenseCategoryItem>> GetHierarchyAsync();

        /// <summary>
        /// Lấy danh sách danh mục gốc (không có ParentId)
        /// </summary>
        Task<List<ExpenseCategoryItem>> GetRootCategoriesAsync();

        /// <summary>
        /// Lấy danh sách danh mục con theo ParentId
        /// </summary>
        Task<List<ExpenseCategoryItem>> GetChildrenAsync(int parentId);

        /// <summary>
        /// Kiểm tra có thể xóa danh mục không (không có danh mục con)
        /// </summary>
        Task<bool> CanDeleteAsync(int id);
    }

    /// <summary>
    /// Service quản lý danh mục chi phí
    /// </summary>
    public class ExpenseCategoryService : IExpenseCategoryService
    {
        private readonly IRepository<ExpenseCategory> _expenseCategoryRepository;
        private readonly IUserRepository<User> _userRepository;

        public ExpenseCategoryService(IRepository<ExpenseCategory> expenseCategoryRepository, IUserRepository<User> userRepository)
        {
            _expenseCategoryRepository = expenseCategoryRepository;
            _userRepository = userRepository;
        }

        /// <summary>
        /// Tìm kiếm danh mục chi phí với phân trang
        /// Hỗ trợ hai chế độ hiển thị: List (danh sách) và Tree (cây phân cấp)
        /// </summary>
        public async Task<SmartTableResult<ExpenseCategoryItem>> Search(SmartTableParam param)
        {
            param ??= new SmartTableParam();

            var query = _expenseCategoryRepository.Query()
                .Include(x => x.Parent)
                .Where(x => !x.IsDeleted);

            bool isTreeMode = false;

            // Xử lý tìm kiếm
            if (param.Search?.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;

                // Kiểm tra chế độ hiển thị
                if (search.DisplayMode != null)
                {
                    string displayMode = search.DisplayMode.ToString().ToLower();
                    isTreeMode = displayMode == "tree";
                }

                if (search.Keyword != null)
                {
                    string keyword = search.Keyword.ToString().ToLower().Trim();
                    if (!string.IsNullOrEmpty(keyword))
                    {
                        query = query.Where(x => x.Name.ToLower().Contains(keyword) ||
                                               x.Description.ToLower().Contains(keyword));
                    }
                }

                if (search.ParentId != null)
                {
                    int parentId = Convert.ToInt32(search.ParentId);
                    if (parentId == 0)
                    {
                        // Tìm danh mục gốc (ParentId = null)
                        query = query.Where(x => x.ParentId == null);
                    }
                    else
                    {
                        // Tìm danh mục con của ParentId
                        query = query.Where(x => x.ParentId == parentId);
                    }
                }
            }

            // Xử lý theo chế độ hiển thị
            if (isTreeMode)
            {
                // Chế độ cây: Lấy tất cả dữ liệu và xây dựng cây phân cấp
                var allItems = await query
                    .OrderBy(x => x.DisplayOrder)
                    .ThenBy(x => x.Name)
                    .Select(x => x.ToItem())
                    .ToListAsync();

                // Lấy thông tin ApprovedByUserName
                await PopulateApprovedByUserNames(allItems);

                // Xây dựng cây phân cấp
                var treeItems = BuildTreeStructure(allItems);

                // Trả về kết quả dạng cây (không phân trang)
                return new SmartTableResult<ExpenseCategoryItem>
                {
                    Items = treeItems,
                    TotalRecord = treeItems.Count,
                    NumberOfPages = 1
                };
            }
            else
            {
                // Chế độ danh sách: Sử dụng phân trang thông thường
                var result = await query.ToSmartTableResultAsync(param, x => x.ToItem());

                // Lấy thông tin ApprovedByUserName
                if (result.Items.Any())
                {
                    await PopulateApprovedByUserNames(result.Items.ToList());
                }

                return result;
            }
        }

        /// <summary>
        /// Lấy danh mục chi phí theo ID
        /// </summary>
        public async Task<ExpenseCategoryItem?> GetByIdAsync(int id)
        {
            var entity = await _expenseCategoryRepository.Query()
                .FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted);

            return entity?.ToItem();
        }

        /// <summary>
        /// Tạo hoặc cập nhật danh mục chi phí
        /// </summary>
        public async Task<BaseResult> CreateOrUpdateAsync(ExpenseCategoryModel model, CurrentUser currentUser)
        {
            var result = new BaseResult { Result = Result.Success };

            try
            {
                // Kiểm tra tên trùng
                if (await IsNameExistsAsync(model.Name, model.Id))
                {
                    result.Result = Result.Failed;
                    result.Message = "Tên danh mục chi phí đã tồn tại";
                    return result;
                }

                // Kiểm tra ParentId hợp lệ (không được là chính nó khi update)
                if (model.ParentId.HasValue && model.ParentId.Value == model.Id)
                {
                    result.Result = Result.Failed;
                    result.Message = "Danh mục không thể là cha của chính nó";
                    return result;
                }

                // Kiểm tra ParentId có tồn tại không
                if (model.ParentId.HasValue)
                {
                    var parentExists = await _expenseCategoryRepository.Query()
                        .AnyAsync(x => x.Id == model.ParentId.Value && !x.IsDeleted);
                    if (!parentExists)
                    {
                        result.Result = Result.Failed;
                        result.Message = "Danh mục cha không tồn tại";
                        return result;
                    }
                }

                // Kiểm tra là tạo mới hay cập nhật
                if (model.Id <= 0)
                {
                    // Tạo mới
                    var entity = model.ToEntity();
                    entity.CreatedTime = DateTimeHelper.CurrentTime();
                    entity.UpdatedTime = DateTimeHelper.CurrentTime();
                    entity.CreatedBy = currentUser.UserId;
                    entity.CreatedByUserName = currentUser.UserName;
                    entity.UpdatedBy = currentUser.UserId;
                    entity.UpdatedByUserName = currentUser.UserName;

                    await _expenseCategoryRepository.InsertAsync(entity);
                    result.Message = "Tạo danh mục chi phí thành công";
                }
                else
                {
                    // Cập nhật
                    var entity = await _expenseCategoryRepository.Query()
                        .FirstOrDefaultAsync(x => x.Id == model.Id && !x.IsDeleted);

                    if (entity == null)
                    {
                        result.Result = Result.Failed;
                        result.Message = "Không tìm thấy danh mục chi phí";
                        return result;
                    }

                    // Cập nhật thông tin
                    entity.Name = model.Name;
                    entity.Description = model.Description;
                    entity.DisplayOrder = model.DisplayOrder;
                    entity.ParentId = model.ParentId;
                    entity.ApprovedBy = model.ApprovedBy;
                    entity.AccountCode = model.AccountCode;
                    entity.UpdatedTime = DateTimeHelper.CurrentTime();
                    entity.UpdatedBy = currentUser.UserId;
                    entity.UpdatedByUserName = currentUser.UserName;

                    await _expenseCategoryRepository.UpdateAsync(entity);
                    result.Message = "Cập nhật danh mục chi phí thành công";
                }
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi hệ thống: {ex.Message}";
            }

            return result;
        }

        /// <summary>
        /// Xóa danh mục chi phí
        /// </summary>
        public async Task<BaseResult> DeleteAsync(int id, CurrentUser currentUser)
        {
            var result = new BaseResult { Result = Result.Success };

            try
            {
                var entity = await _expenseCategoryRepository.Query()
                    .FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted);

                if (entity == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy danh mục chi phí";
                    return result;
                }

                // Kiểm tra có danh mục con không
                var hasChildren = await _expenseCategoryRepository.Query()
                    .AnyAsync(x => x.ParentId == id && !x.IsDeleted);
                if (hasChildren)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không thể xóa danh mục có danh mục con";
                    return result;
                }

                // Soft delete
                entity.IsDeleted = true;
                entity.UpdatedTime = DateTimeHelper.CurrentTime();
                entity.UpdatedBy = currentUser.UserId;
                entity.UpdatedByUserName = currentUser.UserName;

                await _expenseCategoryRepository.UpdateAsync(entity);
                result.Message = "Xóa danh mục chi phí thành công";
            }
            catch (Exception ex)
            {
                result.Result = Result.SystemError;
                result.Message = $"Lỗi hệ thống: {ex.Message}";
            }

            return result;
        }

        /// <summary>
        /// Lấy danh sách tất cả danh mục chi phí (cho dropdown)
        /// </summary>
        public async Task<List<ExpenseCategoryItem>> GetAllAsync()
        {
            return await _expenseCategoryRepository.Query()
                .Where(x => !x.IsDeleted)
                .OrderBy(x => x.DisplayOrder)
                .ThenBy(x => x.Name)
                .Select(x => x.ToItem())
                .ToListAsync();
        }

        /// <summary>
        /// Kiểm tra tên danh mục có trùng không
        /// </summary>
        public async Task<bool> IsNameExistsAsync(string name, int excludeId = 0)
        {
            return await _expenseCategoryRepository.Query()
                .AnyAsync(x => x.Name.ToLower() == name.ToLower() &&
                              x.Id != excludeId &&
                              !x.IsDeleted);
        }

        /// <summary>
        /// Lấy danh sách danh mục chi phí theo cây phân cấp
        /// </summary>
        public async Task<List<ExpenseCategoryItem>> GetHierarchyAsync()
        {
            var allCategories = await _expenseCategoryRepository.Query()
                .Include(x => x.Parent)
                .Where(x => !x.IsDeleted)
                .OrderBy(x => x.DisplayOrder)
                .ThenBy(x => x.Name)
                .Select(x => x.ToItem())
                .ToListAsync();

            // Xây dựng cây phân cấp
            var rootCategories = allCategories.Where(x => x.ParentId == null).ToList();
            var childCategories = allCategories.Where(x => x.ParentId != null).ToList();

            foreach (var root in rootCategories)
            {
                BuildHierarchy(root, childCategories, 0);
            }

            return rootCategories;
        }

        /// <summary>
        /// Lấy danh sách danh mục gốc (không có ParentId)
        /// </summary>
        public async Task<List<ExpenseCategoryItem>> GetRootCategoriesAsync()
        {
            return await _expenseCategoryRepository.Query()
                .Where(x => !x.IsDeleted && x.ParentId == null)
                .OrderBy(x => x.DisplayOrder)
                .ThenBy(x => x.Name)
                .Select(x => x.ToItem())
                .ToListAsync();
        }

        /// <summary>
        /// Lấy danh sách danh mục con theo ParentId
        /// </summary>
        public async Task<List<ExpenseCategoryItem>> GetChildrenAsync(int parentId)
        {
            return await _expenseCategoryRepository.Query()
                .Where(x => !x.IsDeleted && x.ParentId == parentId)
                .OrderBy(x => x.DisplayOrder)
                .ThenBy(x => x.Name)
                .Select(x => x.ToItem())
                .ToListAsync();
        }

        /// <summary>
        /// Kiểm tra có thể xóa danh mục không (không có danh mục con)
        /// </summary>
        public async Task<bool> CanDeleteAsync(int id)
        {

            return !await _expenseCategoryRepository.Query()
                .AnyAsync(x => x.ParentId == id && !x.IsDeleted);
        }

        /// <summary>
        /// Lấy thông tin tên người duyệt cho danh sách items
        /// </summary>
        private async Task PopulateApprovedByUserNames(List<ExpenseCategoryItem> items)
        {
            var approvedByIds = items.Where(x => x.ApprovedBy > 0).Select(x => x.ApprovedBy).Distinct().ToList();
            if (approvedByIds.Any())
            {
                var users = await _userRepository.Query()
                    .Where(u => approvedByIds.Contains(u.Id))
                    .Select(u => new { u.Id, u.UserName })
                    .ToListAsync();

                foreach (var item in items)
                {
                    if (item.ApprovedBy > 0)
                    {
                        var user = users.FirstOrDefault(u => u.Id == item.ApprovedBy);
                        item.ApprovedByUserName = user?.UserName ?? "";
                    }
                }
            }
        }

        /// <summary>
        /// Xây dựng cấu trúc cây từ danh sách phẳng
        /// </summary>
        private List<ExpenseCategoryItem> BuildTreeStructure(List<ExpenseCategoryItem> allItems)
        {
            // Lấy danh mục gốc
            var rootItems = allItems.Where(x => x.ParentId == null).ToList();
            var childItems = allItems.Where(x => x.ParentId != null).ToList();

            // Xây dựng cây phân cấp cho từng danh mục gốc
            foreach (var root in rootItems)
            {
                BuildHierarchy(root, childItems, 0);
            }

            return rootItems;
        }

        /// <summary>
        /// Xây dựng cây phân cấp đệ quy
        /// </summary>
        private void BuildHierarchy(ExpenseCategoryItem parent, List<ExpenseCategoryItem> allCategories, int level)
        {
            parent.Level = level;
            var children = allCategories.Where(x => x.ParentId == parent.Id).ToList();

            foreach (var child in children)
            {
                BuildHierarchy(child, allCategories, level + 1);
                parent.Children.Add(child);
            }
        }
    }
}
