using System.Data;
using System.Linq.Dynamic.Core;
using Dapper;
using Lada.Framework.Data.Domains;
using Lada.Framework.Data.Domains.Crm;
using Lada.Framework.Data.Domains.Finance;
using Lada.Framework.Data.Domains.Finance.Wallets;
using Lada.Framework.Data.Domains.Identity;
using Lada.Framework.Data.Domains.Medias;
using Lada.Framework.Data.Domains.Orders;
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.Extensions;
using Lada.Framework.Infrastructures.Helpers;
using Lada.Framework.Infrastructures.Services;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Crm;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Finance;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Finance;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Orders;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Finance;
using Ladaer.BackEnd.Infrastructures.DTO.StoredProcedureResults;
using Ladaer.BackEnd.Infrastructures.Services.Finances;
using Ladaer.BackEnd.Infrastructures.Services.Identity;
using Ladaer.BackEnd.Infrastructures.Services.Orders;
using Microsoft.EntityFrameworkCore;
using static Lada.Framework.Data.Enums.OrderFinEnum;

namespace Ladaer.BackEnd.Infrastructures.Services.Finance
{
    public class CustomerReconciliationSlipService : ICustomerReconciliationSlipService
    {
        private readonly IRepository<CustomerReconciliationSlip> _slipRepository;
        private readonly IRepository<CustomerReconciliationSlipDetail> _slipDetailRepository;
        private readonly IRepository<CustomerReconciliationLog> _logRepository;
        private readonly IRepository<Order> _orderRepository;
        private readonly IRepository<OrderFin> _orderFinRepository;
        private readonly IRepository<Customer> _customerRepository;
        private readonly IRepository<CustomerBankAccount> _customerBankAccountRepository;
        private readonly IRepository<Media> _mediaRepository;
        private readonly IRepository<Wallet> _walletRepository;
        private readonly IRepository<Transaction> _transactionRepository;
        private readonly IUserService _userService;
        private readonly IUnifiedMediaService _unifiedMediaService;
        private readonly IOrderTrackService _orderTrackService;
        private readonly IOrderTimeTrackService _orderTimeTrackService;
        private readonly IDbConnection _dbConnection;

        public CustomerReconciliationSlipService(
            IRepository<CustomerReconciliationSlip> slipRepository,
            IRepository<CustomerReconciliationSlipDetail> slipDetailRepository,
            IRepository<CustomerReconciliationLog> logRepository,
            IRepository<Order> orderRepository,
            IRepository<OrderFin> orderFinRepository,
            IRepository<Customer> customerRepository,
            IRepository<CustomerBankAccount> customerBankAccountRepository,
            IRepository<Media> mediaRepository,
            IRepository<Wallet> walletRepository,
            IRepository<Transaction> transactionRepository,
            IUserService userService,
            IUnifiedMediaService unifiedMediaService,
            IOrderTrackService orderTrackService,
            IOrderTimeTrackService orderTimeTrackService,
            IDbConnection dbConnection)
        {
            _slipRepository = slipRepository;
            _slipDetailRepository = slipDetailRepository;
            _logRepository = logRepository;
            _orderRepository = orderRepository;
            _orderFinRepository = orderFinRepository;
            _customerRepository = customerRepository;
            _customerBankAccountRepository = customerBankAccountRepository;
            _mediaRepository = mediaRepository;
            _walletRepository = walletRepository;
            _transactionRepository = transactionRepository;
            _userService = userService;
            _unifiedMediaService = unifiedMediaService;
            _orderTrackService = orderTrackService;
            _orderTimeTrackService = orderTimeTrackService;
            _dbConnection = dbConnection;
        }

        #region Overview & Search

        public async Task<SmartTableResult<CustomerTransferPaymentSummaryItem>> GetCustomersOverviewAsync(SmartTableParam param, int userId)
        {
            // 1. Check permissions & Get ManagerId filter
            var userRoles = await _userService.GetRolesAsync(userId);
            var isAccountant = userRoles.Any(r => r.Equals("Accountant", StringComparison.OrdinalIgnoreCase));
            var isFounder = userRoles.Any(r => r.Equals("Founder", StringComparison.OrdinalIgnoreCase));

            // Sale chỉ thấy khách của mình
            int? filterManagerId = (!isFounder && !isAccountant) ? userId : null;

            // 2. Extract parameters from SmartTableParam
            string searchKeyword = null;
            DateTimeOffset? fromDate = null;
            DateTimeOffset? toDate = null;

            if (param.Search?.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;
                if (search.Keyword != null)
                {
                    searchKeyword = search.Keyword?.ToString()?.Trim();
                }
                if (search.FromDate != null)
                {
                    fromDate = search.FromDate;
                }
                if (search.ToDate != null)
                {
                    toDate = search.ToDate;
                }
            }

            int pageNumber = param.Pagination?.PageIndex ?? 1;
            int pageSize = param.Pagination?.PageSize ?? 200;

            // 3. Call stored procedure
            var parameters = new DynamicParameters();
            parameters.Add("@SearchKeyword", searchKeyword);
            parameters.Add("@FromDate", fromDate);
            parameters.Add("@ToDate", toDate);
            parameters.Add("@ManagerId", filterManagerId);
            parameters.Add("@PageNumber", pageNumber);
            parameters.Add("@PageSize", pageSize);

            var spResults = await _dbConnection.QueryAsync<CustomerReconciliationSpResult>(
                "sp_SearchCustomersForReconciliation",
                parameters,
                commandType: CommandType.StoredProcedure
            );

            var resultList = spResults.ToList();
            var totalRecord = resultList.FirstOrDefault()?.TotalRecords ?? 0;

            // 4. Map to DTO
            var items = resultList.Select(x => new CustomerTransferPaymentSummaryItem
            {
                CustomerId = x.CustomerId,
                CustomerName = x.FullName,
                CustomerPhone = x.PhoneNumber,
                CustomerCode = x.UserName,
                CustomerEmail = x.Email,
                PendingOrderCount = x.TotalOrderCount,
                CodOrderCount = x.CodOrderCount,
                BankTransferOrderCount = x.BankTransferOrderCount,
                TotalCodAmount = x.TotalCodAmount,
                TotalCodFee = x.TotalCodFee,
                TotalTransferFee = x.TotalTransferFee,
                EstimatedNetAmount = x.EstimatedNetAmount,
                OldestOrderDate = x.OldestOrderDate,
                LatestOrderDate = x.LatestOrderDate,
                CanCreateBill = true
            }).ToList();

            return new SmartTableResult<CustomerTransferPaymentSummaryItem>
            {
                Items = items,
                TotalRecord = totalRecord,
                NumberOfPages = (int)Math.Ceiling((double)totalRecord / pageSize)
            };
        }

        public async Task<List<CustomerReconciliationSlipDetailItem>> GetReconciliableOrdersAsync(int customerId, int userId)
        {
            // Check permission
            var userRoles = await _userService.GetRolesAsync(userId);
            var isFounder = userRoles.Any(r => r.Equals("Founder", StringComparison.OrdinalIgnoreCase));
            var isAccountant = userRoles.Any(r => r.Equals("CustomerReconciliationSlip.View", StringComparison.OrdinalIgnoreCase));

            var customer = await _customerRepository.GetByIdAsync(customerId);
            if (customer == null) throw new Exception("Khách hàng không tồn tại");

            if (!isFounder && !isAccountant && customer.ManagerId != userId)
            {
                throw new Exception("Bạn không có quyền truy cập dữ liệu khách hàng này");
            }

            // Call stored procedure
            var parameters = new DynamicParameters();
            parameters.Add("@CustomerId", customerId);

            var spResults = await _dbConnection.QueryAsync<ReconciliableOrderSpResult>(
                "sp_GetReconciliableOrdersByCustomer",
                parameters,
                commandType: CommandType.StoredProcedure
            );

            var orders = spResults.ToList();

            return orders.Select(x => new CustomerReconciliationSlipDetailItem
            {
                OrderId = x.OrderId,
                OrderCode = x.OrderCode,
                PartnerCode = x.PartnerCode,
                CustomerCode = x.CustomerCode,
                AppliedCodAmount = x.AppliedCodAmount,
                AppliedFeeAmount = x.AppliedFeeAmount,
                NetAmount = x.NetAmount,
                DeliveredDate = x.DeliveredDate,
                CodCollectedDate = x.CodCollectedDate,
                OrderStatus = ((OrderStatus)x.OrderStatus).GetDescription(),
                OrderStatusCssClass = ((OrderStatus)x.OrderStatus).GetStatusTagClass(),
                PhysicalStatus = ((OrderPhysicalStatus)x.PhysicalStatus).GetDescription(),
                PhysicalStatusCssClass = ((OrderPhysicalStatus)x.PhysicalStatus).GetPhysicalStatusTagClass(),
                ChargeWeight = x.ChargeWeight,
                ShippingFee = x.ShippingFee,
                SenderAddress = x.SenderAddress,
                SenderName = x.SenderName,
                SenderPhone = x.SenderPhone,
                DeliveryAddress = x.DeliveryAddress,
                ReceiverName = x.ReceiverName,
                ReceiverPhone = x.ReceiverPhone,
                Note = x.Note,
                ProductInfo = x.ProductInfo
            }).ToList();
        }

        public async Task<SmartTableResult<CustomerReconciliationSlipItem>> GetSlipsAsync(SmartTableParam param, int userId)
        {
            var userRoles = await _userService.GetRolesAsync(userId);
            var isFounder = userRoles.Any(r => r.Equals("Founder", StringComparison.OrdinalIgnoreCase));
            var isAccountant = userRoles.Any(r => r.Equals("Accountant", StringComparison.OrdinalIgnoreCase));

            IQueryable<CustomerReconciliationSlip> query = _slipRepository.Query()
                .Include(x => x.Customer)
                .Include(x => x.TaxInvoice);

            // Filter permission
            if (!isFounder && !isAccountant)
            {
                query = query.Where(x => x.CreatedBy == userId || x.Customer.ManagerId == userId);
            }

            // Search
            if (param.Search?.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;
                string keyword = search.Keyword;
                if (!string.IsNullOrEmpty(keyword))
                {
                    query = query.Where(x => x.Code.Contains(keyword) || x.Customer.FullName.Contains(keyword)
                    || x.Customer.PhoneNumber.Contains(keyword));
                }

                if (search.Status != null)
                {
                    CustomerReconciliationSlipStatus status = search.Status;
                    query = query.Where(x => x.Status == status);
                }

                if (search.Type != null)
                {
                    CustomerReconciliationSlipType type = search.Type;
                    query = query.Where(x => x.Type == type);
                }

                // Lọc theo việc có hóa đơn hay không
                if (search.HasTaxInvoice != null)
                {
                    bool hasTaxInvoice = search.HasTaxInvoice;
                    if (hasTaxInvoice)
                    {
                        query = query.Where(x => x.TaxInvoiceId != null);
                    }
                    else
                    {
                        query = query.Where(x => x.TaxInvoiceId == null);
                    }
                }

                // Lọc theo trạng thái hóa đơn
                if (search.TaxInvoiceStatus != null)
                {
                    TaxInvoiceStatus taxInvoiceStatus = search.TaxInvoiceStatus;
                    query = query.Where(x => x.TaxInvoice != null && x.TaxInvoice.Status == taxInvoiceStatus);
                }

                // Lọc theo ngày tạo phiếu
                if (search.CreatedStart != null && search.CreatedEnd != null)
                {
                    DateTimeOffset start = search.CreatedStart;
                    DateTimeOffset end = search.CreatedEnd;
                    DateTimeOffset startParam = start.ToLocalTime().StartOfDay();
                    DateTimeOffset endParam = end.EndOfDay().ToLocalTime().EndOfDay();
                    query = query.Where(x => x.CreatedTime >= startParam && x.CreatedTime <= endParam);
                }
            }

            // Sort
            if (string.IsNullOrEmpty(param.Sort?.Predicate))
            {
                param.Sort = new Sort { Predicate = "CreatedTime", Reverse = true };
            }

            return await query.ToSmartTableResultAsync(param, x => new CustomerReconciliationSlipItem
            {
                Id = x.Id,
                Code = x.Code,
                CustomerId = x.CustomerId,
                CustomerName = x.Customer.FullName,
                CustomerPhone = x.Customer.PhoneNumber,
                Type = x.Type,
                Status = x.Status,
                TotalCodAmount = x.TotalCodAmount,
                TotalFeeAmount = x.TotalFeeAmount,
                FinalAmount = x.FinalAmount,
                OrderCount = x.OrderCount,
                CreatedByUserName = x.CreatedByUserName,
                CreatedTime = x.CreatedTime.GetValueOrDefault(),
                ApprovedByUsername = x.ApprovedByUsername,
                ApprovedTime = x.ApprovedTime,
                CompletedByUsername = x.CompletedByUsername,
                CompletedTime = x.CompletedTime,
                InternalNote = x.InternalNote,
                PaymentMethod = x.PaymentMethod,
                TransactionCode = x.TransactionCode,
                ProofImageUrl = x.ProofImageUrl,
                // Thông tin hóa đơn
                HasTaxInvoice = x.TaxInvoiceId != null,
                TaxInvoiceStatus = x.TaxInvoice != null ? x.TaxInvoice.Status : (TaxInvoiceStatus?)null
            });
        }

        public async Task<CustomerReconciliationSlipResult> GetSlipByIdAsync(int id, int userId)
        {
            var slip = await _slipRepository.Query()
                .Include(x => x.Customer)
                .Include(x => x.Details)
                .Include(x => x.Logs)
                .Include(x => x.Media)
                .FirstOrDefaultAsync(x => x.Id == id);

            if (slip == null) throw new Exception("Phiếu không tồn tại");

            // Check permission
            var userRoles = await _userService.GetRolesAsync(userId);
            var isFounder = userRoles.Any(r => r.Equals("Founder", StringComparison.OrdinalIgnoreCase));
            var isAccountant = userRoles.Any(r => r.Equals("Accountant", StringComparison.OrdinalIgnoreCase));
            var hasViewPermission = userRoles.Any(r => r.Equals("CustomerReconciliationSlip.View", StringComparison.OrdinalIgnoreCase));
            var hasApprovePermission = userRoles.Any(r => r.Equals("CustomerReconciliationSlip.Approve", StringComparison.OrdinalIgnoreCase));
            var hasRejectPermission = userRoles.Any(r => r.Equals("CustomerReconciliationSlip.Reject", StringComparison.OrdinalIgnoreCase));
            var hasCompletePermission = userRoles.Any(r => r.Equals("CustomerReconciliationSlip.Complete", StringComparison.OrdinalIgnoreCase));
            var isCreator = slip.CreatedBy == userId;

            if (!isFounder && !isAccountant && !hasViewPermission && slip.Customer.ManagerId != userId && !isCreator)
            {
                throw new Exception("Bạn không có quyền xem phiếu này");
            }

            // Calculate permissions based on slip type
            bool canApprove = false;
            bool canReject = false;
            bool canComplete = false;

            if (slip.Type == CustomerReconciliationSlipType.Payable)
            {
                // Phiếu thu tiền (phiếu đối soát âm - khách chuyển tiền cho công ty)
                // Không có duyệt, chỉ có hoàn thành và từ chối

                // Có thể hoàn thành: Founder hoặc Accountant hoặc quyền Complete
                canComplete = isFounder || isAccountant || hasCompletePermission;

                // Có thể từ chối: là người tạo hoặc Founder hoặc Accountant hoặc quyền Reject
                canReject = isCreator || isFounder || isAccountant || hasRejectPermission;
            }
            else if (slip.Type == CustomerReconciliationSlipType.Receivable)
            {
                // Phiếu chi tiền (phiếu đối soát dương - công ty chuyển tiền cho khách)
                // Có duyệt, từ chối và hoàn thành

                // Có thể duyệt: Founder hoặc Accountant hoặc quyền Approve
                canApprove = isFounder || isAccountant || hasApprovePermission;

                // Có thể từ chối: là người tạo hoặc Founder hoặc Accountant hoặc quyền Reject
                canReject = isCreator || isFounder || isAccountant || hasRejectPermission;

                // Có thể hoàn thành: Founder hoặc Accountant hoặc quyền Complete
                canComplete = isFounder || isAccountant || hasCompletePermission;
            }

            var result = new CustomerReconciliationSlipResult
            {
                Slip = new CustomerReconciliationSlipItem
                {
                    Id = slip.Id,
                    Code = slip.Code,
                    CustomerId = slip.CustomerId,
                    CustomerName = slip.Customer.FullName,
                    CustomerPhone = slip.Customer.PhoneNumber,
                    Type = slip.Type,
                    Status = slip.Status,
                    TotalCodAmount = slip.TotalCodAmount,
                    TotalFeeAmount = slip.TotalFeeAmount,
                    FinalAmount = slip.FinalAmount,
                    OrderCount = slip.OrderCount,
                    CreatedByUserName = slip.CreatedByUserName,
                    CreatedTime = slip.CreatedTime.GetValueOrDefault(),
                    ApprovedByUsername = slip.ApprovedByUsername,
                    ApprovedTime = slip.ApprovedTime,
                    CompletedByUsername = slip.CompletedByUsername,
                    CompletedTime = slip.CompletedTime,
                    InternalNote = slip.InternalNote,
                    PaymentMethod = slip.PaymentMethod,
                    TransactionCode = slip.TransactionCode,
                    ProofImageUrl = slip.Media != null && !string.IsNullOrEmpty(slip.Media.SystemPath)
                        ? await _unifiedMediaService.GetUrlBySystemPathAsync(slip.Media.SystemPath)
                        : "",
                    // Thông tin tài khoản ngân hàng nhận tiền (chỉ có với phiếu Receivable)
                    CustomerBankAccountId = slip.CustomerBankAccountId,
                    BankAccountNumber = slip.BankAccountNumber,
                    BankAccountHolderName = slip.BankAccountHolderName,
                    BankCode = slip.BankCode,
                    BankName = slip.BankName,
                    BankBranchName = slip.BankBranchName,
                    BankBranchAddress = slip.BankBranchAddress
                },
                Details = slip.Details.Select(x => new CustomerReconciliationSlipDetailItem
                {
                    Id = x.Id,
                    CustomerReconciliationSlipId = x.CustomerReconciliationSlipId,
                    OrderId = x.OrderId,
                    OrderCode = x.OrderCode,
                    PartnerCode = x.PartnerCode,
                    AppliedCodAmount = x.AppliedCodAmount,
                    AppliedFeeAmount = x.AppliedFeeAmount,
                    NetAmount = x.NetAmount,
                    DeliveredDate = x.DeliveredDate,
                    CodCollectedDate = x.CodCollectedDate,
                    ChargeWeight = x.ChargeWeight,
                    ShippingFee = x.ShippingFee,
                    DeliveryAddress = x.DeliveryAddress,
                    ReceiverName = x.ReceiverName,
                    ReceiverPhone = x.ReceiverPhone,
                    Note = x.Note
                }).ToList(),
                Logs = slip.Logs.OrderByDescending(x => x.CreatedTime).Select(x => new CustomerReconciliationLogItem
                {
                    Id = x.Id,
                    CustomerReconciliationSlipId = x.CustomerReconciliationSlipId,
                    ActorId = x.ActorId,
                    ActorUsername = x.ActorUsername,
                    ActionType = x.ActionType,
                    OldStatus = x.OldStatus,
                    NewStatus = x.NewStatus,
                    Note = x.Note,
                    CreatedTime = x.CreatedTime.GetValueOrDefault()
                }).ToList(),

                // Apply status-based restrictions
                CanApprove = canApprove && slip.Status == CustomerReconciliationSlipStatus.PendingApproval,
                CanReject = canReject && (slip.Status != CustomerReconciliationSlipStatus.Rejected && slip.Status != CustomerReconciliationSlipStatus.Completed),
                // Phiếu Payable (thu tiền) có thể Complete khi đang PendingApproval (không cần Approve)
                // Phiếu Receivable (chi tiền) phải Approved mới Complete được
                CanComplete = canComplete && (
                    (slip.Type == CustomerReconciliationSlipType.Payable && slip.Status == CustomerReconciliationSlipStatus.PendingApproval) ||
                    (slip.Type == CustomerReconciliationSlipType.Receivable && slip.Status == CustomerReconciliationSlipStatus.Approved)
                )
            };

            // Load thông tin tài khoản ngân hàng nếu là phiếu Receivable (công ty cần chuyển tiền cho khách)
            if (slip.Type == CustomerReconciliationSlipType.Receivable)
            {
                var bankAccounts = await _customerBankAccountRepository.Query()
                    .Where(x => x.CustomerId == slip.CustomerId && !x.IsDeleted)
                    .OrderByDescending(x => x.IsDefault)
                    .ThenByDescending(x => x.Id)
                    .Select(x => new CustomerBankAccountItem
                    {
                        Id = x.Id,
                        CustomerId = x.CustomerId,
                        AccountNumber = x.AccountNumber,
                        AccountHolderName = x.AccountHolderName,
                        BankCode = x.BankCode,
                        BankName = x.BankName,
                        BranchName = x.BranchName,
                        BranchAddress = x.BranchAddress,
                        IsDefault = x.IsDefault,
                        Note = x.Note
                    })
                    .ToListAsync();

                result.CustomerBankAccounts = bankAccounts;
            }

            return result;
        }

        #endregion

        #region Actions

        public async Task<int> CreateSlipAsync(CreateCustomerReconciliationSlipModel model, CurrentUser currentUser)
        {
            // Validate permission
            var customer = await _customerRepository.GetByIdAsync(model.CustomerId);
            if (customer == null) throw new Exception("Khách hàng không tồn tại");

            var userRoles = await _userService.GetRolesAsync(currentUser.UserId);
            var isFounder = userRoles.Any(r => r.Equals("Founder", StringComparison.OrdinalIgnoreCase));

            if (!isFounder && customer.ManagerId != currentUser.UserId)
            {
                throw new Exception("Bạn chỉ được tạo phiếu cho khách hàng mình quản lý");
            }

            // Validate orders
            var orders = await _orderRepository.Query()
                .Include(x => x.OrderFin)
                .Include(x => x.Addresses)
                .Where(x => model.OrderIds.Contains(x.Id))
                .ToListAsync();

            if (orders.Count != model.OrderIds.Count) throw new Exception("Một số đơn hàng không tồn tại");
            if (orders.Any(x => x.CustomerId != model.CustomerId)) throw new Exception("Đơn hàng không thuộc khách hàng này");

            // Check locking
            var lockedOrderIds = await _slipDetailRepository.Query()
                .Include(x => x.CustomerReconciliationSlip)
                .Where(x => x.CustomerReconciliationSlip.Status != CustomerReconciliationSlipStatus.Rejected)
                .Where(x => model.OrderIds.Contains(x.OrderId))
                .Select(x => x.OrderId)
                .ToListAsync();

            if (lockedOrderIds.Any()) throw new Exception($"Đơn hàng {string.Join(", ", lockedOrderIds)} đã nằm trong phiếu đối soát khác");

            // Calculate totals
            decimal totalCod = orders.Sum(x => x.OrderFin?.CollectAmount ?? 0);
            decimal totalFee = orders.Sum(x => x.OrderFin?.TotalFee ?? 0);
            decimal finalAmount = Math.Abs(totalCod - totalFee);
            var type = totalCod >= totalFee ? CustomerReconciliationSlipType.Receivable : CustomerReconciliationSlipType.Payable;

            // Validate image for Payable slips (khách chuyển khoản cho công ty)
            if (type == CustomerReconciliationSlipType.Payable)
            {
                if (model.Files == null || model.Files.Count != 1)
                {
                    throw new Exception("Phiếu đối soát âm (khách chuyển khoản cho công ty) yêu cầu upload đúng 1 ảnh chứng từ");
                }

                var uploadedImageFile = model.Files[0];
                var isValidImage = await _unifiedMediaService.ValidateImageAsync(uploadedImageFile);
                if (!isValidImage)
                {
                    throw new Exception("File tải lên không phải là ảnh hợp lệ");
                }
            }

            // Generate Code
            string code = $"CR-{DateTime.Now:yyMMdd}-{Guid.NewGuid().ToString().Substring(0, 4).ToUpper()}";

            var slip = new CustomerReconciliationSlip
            {
                Code = code,
                CustomerId = model.CustomerId,
                Type = type,
                Status = CustomerReconciliationSlipStatus.PendingApproval, // Auto submit
                TotalCodAmount = totalCod,
                TotalFeeAmount = totalFee,
                FinalAmount = finalAmount,
                InternalNote = model.InternalNote,
                OrderCount = orders.Count,
                CreatedBy = currentUser.UserId,
                CreatedByUserName = currentUser.UserName,
                CreatedTime = DateTimeOffset.Now,
                // Thông tin tài khoản ngân hàng nhận tiền (chỉ dùng cho phiếu Receivable)
                BankAccountNumber = type == CustomerReconciliationSlipType.Receivable ? model.BankAccountNumber : null,
                BankAccountHolderName = type == CustomerReconciliationSlipType.Receivable ? model.BankAccountHolderName : null,
                BankCode = type == CustomerReconciliationSlipType.Receivable ? model.BankCode : null,
                BankName = type == CustomerReconciliationSlipType.Receivable ? model.BankName : null,
                BankBranchName = type == CustomerReconciliationSlipType.Receivable ? model.BankBranchName : null,
                BankBranchAddress = type == CustomerReconciliationSlipType.Receivable ? model.BankBranchAddress : null
            };

            await _slipRepository.InsertAsync(slip);

            // Process and save image for Payable slips
            if (type == CustomerReconciliationSlipType.Payable && model.Files != null && model.Files.Count > 0)
            {
                var imageFile = model.Files[0];
                var processResult = await _unifiedMediaService.ProcessImageAsync(imageFile, ImageType.Document);

                if (processResult.Result != Result.Success)
                {
                    // Rollback: Delete the created slip if image processing fails
                    await _slipRepository.DeleteAsync(slip);
                    throw new Exception($"Lỗi khi xử lý ảnh: {processResult.Message}");
                }

                // Save media record to database
                var media = new Media
                {
                    Id = Guid.NewGuid(),
                    SystemPath = processResult.SystemPath,
                    AltText = $"Chứng từ chuyển khoản - {code}",
                    Caption = $"Ảnh chứng từ chuyển khoản cho phiếu đối soát {code}",
                    DisplayOrder = 1,
                    CreatedTime = DateTimeOffset.Now,
                    UpdatedTime = DateTimeOffset.Now,
                    CreatedBy = currentUser.UserId,
                    CreatedByUserName = currentUser.UserName,
                    UpdatedBy = currentUser.UserId,
                    UpdatedByUserName = currentUser.UserName
                };

                await _mediaRepository.InsertAsync(media);

                // Update MediaId for CustomerReconciliationSlip
                slip.MediaId = media.Id;
                slip.ProofImageUrl = processResult.SystemPath; // Store system path
                await _slipRepository.UpdateAsync(slip);
            }

            // Details
            foreach (var order in orders)
            {
                var detail = new CustomerReconciliationSlipDetail
                {
                    CustomerReconciliationSlipId = slip.Id,
                    OrderId = order.Id,
                    OrderCode = order.Code,
                    PartnerCode = order.PartnerCode,
                    AppliedCodAmount = order.OrderFin?.CollectAmount ?? 0,
                    AppliedFeeAmount = order.OrderFin?.TotalFee ?? 0,
                    NetAmount = (order.OrderFin?.CollectAmount ?? 0) - (order.OrderFin?.TotalFee ?? 0),
                    ChargeWeight = order.OrderFin?.ChargeWeight ?? 0,
                    ShippingFee = order.OrderFin?.Fee ?? 0,
                    DeliveryAddress = order.Addresses?.FirstOrDefault(a => a.AddressType == AddressType.Dest)?.Address1 ?? "",
                    ReceiverName = order.Addresses?.FirstOrDefault(a => a.AddressType == AddressType.Dest)?.Name ?? "",
                    ReceiverPhone = order.Addresses?.FirstOrDefault(a => a.AddressType == AddressType.Dest)?.PhoneNumber1 ?? "",
                    CreatedBy = currentUser.UserId,
                    CreatedByUserName = currentUser.UserName,
                    CreatedTime = DateTimeOffset.Now
                };
                await _slipDetailRepository.InsertAsync(detail);

                if (order.OrderFin?.PayFeeType == PayFeeType.BankTransfer)
                {
                    // Update order TransferFeeCashier info
                    order.OrderFin!.TransferFeeCashierId = currentUser.UserId;
                    order.OrderFin!.TransferFeeCashierUsername = currentUser.UserName;
                    order.OrderFin!.TransferFeeStage = OrderFeeStage.Sale;
                    await _orderFinRepository.UpdateAsync(order.OrderFin);
                }

            }

            // Tạo OrderTrack cho các đơn hàng
            await CreateOrderTracksAsync(
                orders.Select(o => o.Id).ToList(),
                slip.Code,
                $"Đơn hàng được đưa vào phiếu đối soát {slip.Code}",
                TrackActionType.ReconciliationCreate,
                currentUser
            );

            // Log
            await LogAction(slip.Id, currentUser, CustomerReconciliationActionType.Create, "Tạo mới phiếu đối soát");

            return slip.Id;
        }

        public async Task ApproveSlipAsync(int id, CurrentUser currentUser)
        {
            var slip = await _slipRepository.Query()
                .Include(x => x.Details)
                .FirstOrDefaultAsync(x => x.Id == id);

            if (slip == null) throw new Exception("Phiếu không tồn tại");

            if (slip.Status == CustomerReconciliationSlipStatus.Rejected)
                throw new Exception("Không thể duyệt phiếu đã bị từ chối");

            if (slip.Status == CustomerReconciliationSlipStatus.Completed)
                throw new Exception("Không thể duyệt phiếu đã hoàn thành");

            if (slip.Status != CustomerReconciliationSlipStatus.PendingApproval)
                throw new Exception("Trạng thái phiếu không hợp lệ");

            var oldStatus = slip.Status;
            slip.Status = CustomerReconciliationSlipStatus.Approved;
            slip.ApprovedBy = currentUser.UserId;
            slip.ApprovedByUsername = currentUser.UserName;
            slip.ApprovedTime = DateTimeOffset.Now;

            await _slipRepository.UpdateAsync(slip);

            // Tạo OrderTrack cho các đơn hàng
            var orderIds = slip.Details.Select(d => d.OrderId).ToList();
            await CreateOrderTracksAsync(
                orderIds,
                slip.Code,
                $"Phiếu đối soát {slip.Code} đã được duyệt bởi {currentUser.UserName}",
                TrackActionType.ReconciliationApprove,
                currentUser
            );

            await LogAction(id, currentUser, CustomerReconciliationActionType.Approve, "Duyệt phiếu", oldStatus.ToString(), slip.Status.ToString());
        }

        public async Task RejectSlipAsync(RejectCustomerReconciliationSlipModel model, CurrentUser currentUser)
        {
            var slip = await _slipRepository.Query()
                .Include(x => x.Details)
                .FirstOrDefaultAsync(x => x.Id == model.Id);

            if (slip == null) throw new Exception("Phiếu không tồn tại");
            if (slip.Status == CustomerReconciliationSlipStatus.Completed || slip.Status == CustomerReconciliationSlipStatus.Rejected)
                throw new Exception("Không thể từ chối phiếu ở trạng thái này");

            var oldStatus = slip.Status;
            slip.Status = CustomerReconciliationSlipStatus.Rejected;
            slip.InternalNote = model.Reason;

            await _slipRepository.UpdateAsync(slip);

            // Khôi phục lại trạng thái TransferFeeStage cho các đơn chuyển khoản kế toán
            var orderIds = slip.Details.Select(d => d.OrderId).ToList();
            var orders = await _orderRepository.Query()
                .Include(o => o.OrderFin)
                .Where(o => orderIds.Contains(o.Id))
                .ToListAsync();

            foreach (var order in orders)
            {
                if (order.OrderFin?.PayFeeType == PayFeeType.BankTransfer)
                {
                    // Reset lại TransferFeeStage về NotCollected (trạng thái ban đầu)
                    order.OrderFin!.TransferFeeCashierId = 0;
                    order.OrderFin!.TransferFeeCashierUsername = "";
                    order.OrderFin!.TransferFeeStage = OrderFeeStage.NotCollected;
                    await _orderFinRepository.UpdateAsync(order.OrderFin);
                }
            }

            // Tạo OrderTrack cho các đơn hàng
            await CreateOrderTracksAsync(
                orderIds,
                slip.Code,
                $"Phiếu đối soát {slip.Code} bị từ chối bởi {currentUser.UserName}. Lý do: {model.Reason}",
                TrackActionType.ReconciliationReject,
                currentUser
            );

            await LogAction(model.Id, currentUser, CustomerReconciliationActionType.Reject, $"Từ chối: {model.Reason}", oldStatus.ToString(), slip.Status.ToString());
        }

        public async Task CompleteSlipAsync(CompleteCustomerReconciliationSlipModel model, CurrentUser currentUser)
        {
            var slip = await _slipRepository.Query()
                .Include(x => x.Details)
                .FirstOrDefaultAsync(x => x.Id == model.Id);

            if (slip == null) throw new Exception("Phiếu không tồn tại");

            if (slip.Status == CustomerReconciliationSlipStatus.Rejected)
                throw new Exception("Không thể hoàn thành phiếu đã bị từ chối");

            if (slip.Status == CustomerReconciliationSlipStatus.Completed)
                throw new Exception("Phiếu đã được hoàn thành trước đó");

            ValidateSlipStatusForCompletion(slip);

            var oldStatus = slip.Status;
            slip.Status = CustomerReconciliationSlipStatus.Completed;
            slip.ProofImageUrl = model.ProofImageUrl;
            slip.CompletedBy = currentUser.UserId;
            slip.CompletedByUsername = currentUser.UserName;
            slip.CompletedTime = DateTimeOffset.Now;

            if (slip.Type == CustomerReconciliationSlipType.Payable)
            {
                await CompletePayableSlipAsync(slip, model, currentUser);
            }
            else if (slip.Type == CustomerReconciliationSlipType.Receivable)
            {
                await CompleteReceivableSlipAsync(slip, model, currentUser);
            }
            else
            {
                await _slipRepository.UpdateAsync(slip);
            }

            await LogAction(model.Id, currentUser, CustomerReconciliationActionType.ConfirmPayment, "Xác nhận hoàn thành thanh toán", oldStatus.ToString(), slip.Status.ToString());
        }

        public async Task<List<CustomerReconciliationLogItem>> GetSlipLogsAsync(int id, int userId)
        {
            // Check permission (reuse existing logic or simplify)
            var logs = await _logRepository.Query()
               .Where(x => x.CustomerReconciliationSlipId == id)
               .OrderByDescending(x => x.CreatedTime)
               .ToListAsync();

            return logs.Select(x => new CustomerReconciliationLogItem
            {
                Id = x.Id,
                CustomerReconciliationSlipId = x.CustomerReconciliationSlipId,
                ActorId = x.ActorId,
                ActorUsername = x.ActorUsername,
                ActionType = x.ActionType,
                OldStatus = x.OldStatus,
                NewStatus = x.NewStatus,
                Note = x.Note,
                CreatedTime = x.CreatedTime.GetValueOrDefault()
            }).ToList();
        }

        #region Complete Slip Helper Methods

        /// <summary>
        /// Validate trạng thái phiếu trước khi hoàn thành
        /// </summary>
        private void ValidateSlipStatusForCompletion(CustomerReconciliationSlip slip)
        {
            bool canCompleteFromCurrentStatus =
                (slip.Type == CustomerReconciliationSlipType.Payable && slip.Status == CustomerReconciliationSlipStatus.PendingApproval) ||
                (slip.Type == CustomerReconciliationSlipType.Receivable && slip.Status == CustomerReconciliationSlipStatus.Approved);

            if (!canCompleteFromCurrentStatus)
            {
                if (slip.Type == CustomerReconciliationSlipType.Payable)
                    throw new Exception("Phiếu thu tiền phải ở trạng thái Chờ duyệt mới có thể hoàn thành");
                else
                    throw new Exception("Phiếu chi tiền phải được duyệt trước khi hoàn thành");
            }
        }

        /// <summary>
        /// Lấy hoặc tạo ví Personal cho user
        /// </summary>
        private async Task<Wallet> GetOrCreateWalletAsync(CurrentUser currentUser)
        {
            var wallet = await _walletRepository.Query()
                .FirstOrDefaultAsync(w => w.UserId == currentUser.UserId && w.WalletType == WalletType.Personal);

            if (wallet == null)
            {
                wallet = new Wallet
                {
                    UserId = currentUser.UserId,
                    Balance = 0,
                    WalletType = WalletType.Personal,
                    WalletStatus = WalletStatus.Active
                };
                wallet = wallet.UpdateCommonInt(currentUser.UserId, currentUser.UserName);
                await _walletRepository.InsertAsync(wallet);
            }

            return wallet;
        }

        /// <summary>
        /// Tạo giao dịch ví cho phiếu đối soát (dùng chung cho cả Payable và Receivable)
        /// </summary>
        private async Task CreateWalletTransactionAsync(
            CustomerReconciliationSlip slip,
            CompleteCustomerReconciliationSlipModel model,
            CurrentUser currentUser,
            bool isIncome)
        {
            using (var dbtransaction = _walletRepository.BeginTransaction())
            {
                try
                {
                    var wallet = await GetOrCreateWalletAsync(currentUser);

                    // Nếu là chi tiền, kiểm tra số dư
                    if (!isIncome && wallet.Balance < slip.FinalAmount)
                    {
                        throw new Exception($"Số dư ví không đủ. Số dư hiện tại: {wallet.Balance:N0} VNĐ, cần: {slip.FinalAmount:N0} VNĐ");
                    }

                    // Tạo giao dịch
                    var transaction = new Transaction
                    {
                        Description = isIncome
                            ? $"Nhận tiền đối soát từ phiếu {slip.Code}"
                            : $"Chuyển tiền đối soát {slip.Code} cho khách hàng",
                        WalletId = wallet.Id,
                        Amount = slip.FinalAmount,
                        CashAmount = 0,
                        TransferAmount = slip.FinalAmount,
                        Note = model.Note,
                        FromUserId = isIncome ? slip.CustomerId : currentUser.UserId,
                        TransactionType = isIncome ? TransactionType.CollectFromCustomer : TransactionType.Reconciliation,
                        TransactionDate = DateTimeOffset.Now,
                        TransactionDirection = isIncome ? TransactionDirection.Income : TransactionDirection.Outcome
                    };
                    transaction = transaction.UpdateCommonGuid(currentUser.UserId, currentUser.UserName);

                    await _transactionRepository.InsertAsync(transaction);

                    // Cập nhật số dư ví
                    if (isIncome)
                        wallet.Balance += slip.FinalAmount;
                    else
                        wallet.Balance -= slip.FinalAmount;

                    await _walletRepository.UpdateAsync(wallet);

                    // Liên kết giao dịch với phiếu đối soát
                    slip.TransactionId = transaction.Id;
                    await _slipRepository.UpdateAsync(slip);

                    await dbtransaction.CommitAsync();
                }
                catch (Exception ex)
                {
                    await dbtransaction.RollbackAsync();
                    throw new Exception($"Lỗi khi tạo giao dịch ví: {ex.Message}");
                }
            }
        }

        /// <summary>
        /// Hoàn thành phiếu Payable (thu tiền)
        /// </summary>
        private async Task CompletePayableSlipAsync(
            CustomerReconciliationSlip slip,
            CompleteCustomerReconciliationSlipModel model,
            CurrentUser currentUser)
        {
            await CreateWalletTransactionAsync(slip, model, currentUser, isIncome: true);
            await UpdateOrdersForPayableSlipAsync(slip, currentUser);
        }

        /// <summary>
        /// Cập nhật đơn hàng cho phiếu Payable
        /// </summary>
        private async Task UpdateOrdersForPayableSlipAsync(CustomerReconciliationSlip slip, CurrentUser currentUser)
        {
            var orderIds = slip.Details.Select(d => d.OrderId).ToList();
            var orders = await _orderRepository.Query()
                .Include(o => o.OrderFin)
                .Where(o => orderIds.Contains(o.Id))
                .ToListAsync();

            foreach (var order in orders)
            {
                if (order.OrderFin != null)
                {
                    if (order.OrderFin.PayFeeType == PayFeeType.BankTransfer)
                    {
                        order.OrderFin.TransferFeeCashierId = currentUser.UserId;
                        order.OrderFin.TransferFeeCashierUsername = currentUser.UserName;
                        order.OrderFin.TransferFeeStage = OrderFeeStage.Head;
                        await _orderFinRepository.UpdateAsync(order.OrderFin);
                        await _orderTimeTrackService.UpdateFinancialTimesAsync(
                        orderId: order.Id,
                        transferFeeStage: OrderFeeStage.Head,
                        updatedBy: currentUser.UserId,
                        updatedByUserName: currentUser.UserName,
                        currentTime: DateTimeOffset.Now
                        );
                        await _orderTrackService.CreateAsync(new OrderTrackModel
                        {
                            OrderId = order.Id,
                            OrderCode = order.Code,
                            Name = $"Đã nhận tiền từ phiếu đối soát {slip.Code}",
                            TrackActionType = TrackActionType.ReconciliationTransfer,
                            OrderTrackType = OrderTrackType.ForInternal,
                            CreatedBy = currentUser.UserId,
                            CreatedByUserName = currentUser.UserName,
                            PhoneContact = ""
                        });

                    }
                    else if (order.OrderFin.PayFeeType == PayFeeType.COD)
                    {
                        // Cập nhật CodStage
                        order.OrderFin.CodStage = OrderCodStage.Transfered;
                        await _orderFinRepository.UpdateAsync(order.OrderFin);
                        await _orderTrackService.CreateAsync(new OrderTrackModel
                        {
                            OrderId = order.Id,
                            OrderCode = order.Code,
                            Name = $"Đã chuyển tiền đối soát {slip.Code} cho khách hàng",
                            TrackActionType = TrackActionType.ReconciliationTransfer,
                            OrderTrackType = OrderTrackType.ForInternal,
                            CreatedBy = currentUser.UserId,
                            CreatedByUserName = currentUser.UserName,
                            PhoneContact = ""
                        });

                    }


                }
            }
        }

        /// <summary>
        /// Hoàn thành phiếu Receivable (chi tiền)
        /// </summary>
        private async Task CompleteReceivableSlipAsync(
            CustomerReconciliationSlip slip,
            CompleteCustomerReconciliationSlipModel model,
            CurrentUser currentUser)
        {
            await CreateWalletTransactionAsync(slip, model, currentUser, isIncome: false);
            await UpdateOrdersForReceivableSlipAsync(slip, currentUser);
        }

        /// <summary>
        /// Cập nhật đơn hàng cho phiếu Receivable
        /// </summary>
        private async Task UpdateOrdersForReceivableSlipAsync(CustomerReconciliationSlip slip, CurrentUser currentUser)
        {
            var orderIds = slip.Details.Select(d => d.OrderId).ToList();
            var orders = await _orderRepository.Query()
                .Include(o => o.OrderFin)
                .Where(o => orderIds.Contains(o.Id))
                .ToListAsync();

            foreach (var order in orders)
            {
                if (order.OrderFin != null)
                {


                    // Nếu là đơn chuyển khoản kế toán (TransferFee), cập nhật thông tin người giữ tiền và stage
                    if (order.OrderFin.PayFeeType == PayFeeType.BankTransfer)
                    {
                        order.OrderFin.TransferFeeCashierId = currentUser.UserId;
                        order.OrderFin.TransferFeeCashierUsername = currentUser.UserName;
                        order.OrderFin.TransferFeeStage = OrderFeeStage.Head;
                        await _orderFinRepository.UpdateAsync(order.OrderFin);
                        await _orderTimeTrackService.UpdateFinancialTimesAsync(
                        orderId: order.Id,
                        transferFeeStage: OrderFeeStage.Head,
                        updatedBy: currentUser.UserId,
                        updatedByUserName: currentUser.UserName,
                        currentTime: DateTimeOffset.Now
                        );
                        await _orderTrackService.CreateAsync(new OrderTrackModel
                        {
                            OrderId = order.Id,
                            OrderCode = order.Code,
                            Name = $"Đã nhận tiền từ phiếu đối soát {slip.Code}",
                            TrackActionType = TrackActionType.ReconciliationTransfer,
                            OrderTrackType = OrderTrackType.ForInternal,
                            CreatedBy = currentUser.UserId,
                            CreatedByUserName = currentUser.UserName,
                            PhoneContact = ""
                        });
                    }
                    else if (order.OrderFin.PayFeeType == PayFeeType.COD)
                    {
                        // Cập nhật CodStage
                        order.OrderFin.CodStage = OrderCodStage.Transfered;
                        await _orderFinRepository.UpdateAsync(order.OrderFin);
                        await _orderTrackService.CreateAsync(new OrderTrackModel
                        {
                            OrderId = order.Id,
                            OrderCode = order.Code,
                            Name = $"Đã chuyển tiền đối soát {slip.Code} cho khách hàng",
                            TrackActionType = TrackActionType.ReconciliationTransfer,
                            OrderTrackType = OrderTrackType.ForInternal,
                            CreatedBy = currentUser.UserId,
                            CreatedByUserName = currentUser.UserName,
                            PhoneContact = ""
                        });
                    }




                }
            }
        }

        #endregion


        /// <summary>
        /// Tạo OrderTrack cho danh sách đơn hàng (dùng chung)
        /// </summary>
        private async Task CreateOrderTracksAsync(
            List<int> orderIds,
            string slipCode,
            string message,
            TrackActionType actionType,
            CurrentUser currentUser)
        {
            if (orderIds == null || !orderIds.Any())
                return;

            var orders = await _orderRepository.Query()
                .Where(o => orderIds.Contains(o.Id))
                .Select(o => new { o.Id, o.Code })
                .ToListAsync();

            var trackModels = orders.Select(order => new OrderTrackModel
            {
                OrderId = order.Id,
                OrderCode = order.Code,
                Name = message,
                TrackActionType = actionType,
                OrderTrackType = OrderTrackType.ForInternal,
                CreatedBy = currentUser.UserId,
                CreatedByUserName = currentUser.UserName,
                PhoneContact = ""
            }).ToList();

            if (trackModels.Any())
            {
                await _orderTrackService.CreateAsync(trackModels);
            }
        }

        private async Task LogAction(int slipId, CurrentUser actor, CustomerReconciliationActionType action, string note, string oldStatus = "", string newStatus = "")
        {
            var log = new CustomerReconciliationLog
            {
                CustomerReconciliationSlipId = slipId,
                ActorId = actor.UserId,
                ActorUsername = actor.UserName,
                ActionType = action,
                Note = note,
                OldStatus = oldStatus,
                NewStatus = newStatus,
                CreatedBy = actor.UserId,
                CreatedByUserName = actor.UserName,
                CreatedTime = DateTimeOffset.Now
            };
            await _logRepository.InsertAsync(log);
        }

        #endregion
    }
}
