using System;
using Lada.Framework.Data.Domains.Finance.Wallets;
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.Helpers;
using Ladaer.BackEnd.Infrastructures.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Finances;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Finances;
using Ladaer.BackEnd.Infrastructures.Services.Identity;
using Microsoft.EntityFrameworkCore;

namespace Ladaer.BackEnd.Infrastructures.Services.Finances
{
    public interface ITransactionService
    {
        Task<TransactionSearchResult> SearchWalletTransactions(SmartTableParam param, int userId);
        Task<TransactionDetailResult> GetTransactionDetail(Guid transactionId);
        Task<TransactionStatisticsResult> GetTransactionStatistics(int walletId, DateTimeOffset? startDate = null, DateTimeOffset? endDate = null);
        Task<WalletBalanceHistoryResult> GetWalletBalanceHistory(int walletId, DateTimeOffset? startDate = null, DateTimeOffset? endDate = null);
    }

    public class TransactionService : ITransactionService
    {
        private readonly IRepository<Transaction> _transactionRepository;
        private readonly IRepository<Wallet> _walletRepository;
        private readonly IRepository<TransactionOrder> _transactionOrderRepository;
        private readonly IUserService _userService;

        public TransactionService(
            IRepository<Transaction> transactionRepository,
            IRepository<Wallet> walletRepository,
            IRepository<TransactionOrder> transactionOrderRepository,
            IUserService userService)
        {
            _transactionRepository = transactionRepository;
            _walletRepository = walletRepository;
            _transactionOrderRepository = transactionOrderRepository;
            _userService = userService;
        }

        /// <summary>
        /// Tìm kiếm giao dịch của ví.
        /// Chỉ Founder và Accountant mới được xem tất cả giao dịch, user khác chỉ xem ví của mình.
        /// </summary>
        public async Task<TransactionSearchResult> SearchWalletTransactions(SmartTableParam param, int userId)
        {
            var query = _transactionRepository.Query();

            // Kiểm tra quyền của user
            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));

            // Xử lý quyền truy cập
            int? targetWalletId = null;

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

                if (search.WalletId != null && search.WalletId > 0)
                {
                    targetWalletId = search.WalletId;
                }
            }

            // Nếu không phải Founder hoặc Accountant thì chỉ được xem ví của mình
            if (!isFounder && !isAccountant)
            {
                // Tìm ví của user hiện tại
                var userWallet = await _walletRepository.Query()
                    .FirstOrDefaultAsync(w => w.UserId == userId);

                if (userWallet == null)
                {
                    return new TransactionSearchResult();
                }

                targetWalletId = userWallet.Id;
            }

            // Nếu không có walletId thì return empty
            if (!targetWalletId.HasValue)
            {
                return new TransactionSearchResult();
            }

            // Filter theo walletId (chỉ lấy giao dịch thuộc ví này, không lấy RelatedWalletId để tránh double-count)
            query = query.Where(t => t.WalletId == targetWalletId.Value);

            // Áp dụng các filter khác
            if (param.Search.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;

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

                if (search.TransactionType != null)
                {
                    // Xử lý an toàn khi parse enum từ dynamic object
                    if (Enum.TryParse<TransactionType>(search.TransactionType.ToString(), out TransactionType transactionType))
                    {
                        query = query.Where(t => t.TransactionType == transactionType);
                    }
                }

                if (search.TransactionDirection != null)
                {
                    // Xử lý an toàn khi parse enum từ dynamic object
                    if (Enum.TryParse<TransactionDirection>(search.TransactionDirection.ToString(), out TransactionDirection direction))
                    {
                        query = query.Where(t => t.TransactionDirection == direction);
                    }
                }

                if (search.CreatedStart != null && search.CreatedEnd != null)
                {
                    DateTimeOffset start = search.CreatedStart;
                    DateTimeOffset end = search.CreatedEnd;
                    // Chuyển từ UTC sang local time (GMT+7) và lấy đầu/cuối ngày
                    DateTimeOffset startParam = start.ToLocalTime().StartOfDay();
                    DateTimeOffset endParam = end.ToLocalTime().EndOfDay();
                    query = query.Where(t => t.CreatedTime >= startParam && t.CreatedTime <= endParam);
                }
            }

            // Sort mặc định theo CreatedTime desc
            param.Sort = new Sort() { Predicate = "CreatedTime", Reverse = true };

            // Tính tổng thu và tổng chi trước khi phân trang
            var totalIncome = await query
                .Where(t => t.TransactionDirection == TransactionDirection.Income)
                .SumAsync(t => t.Amount);

            var totalOutcome = await query
                .Where(t => t.TransactionDirection == TransactionDirection.Outcome)
                .SumAsync(t => t.Amount);

            // Tính tổng tiền mặt và tổng tiền chuyển khoản
            var totalCash = await query.SumAsync(t => t.CashAmount);
            var totalTransfer = await query.SumAsync(t => t.TransferAmount);

            // Tính toán DailyBalanceHistory dựa trên khoảng thời gian search
            var dailyBalanceHistory = new List<DailyBalanceHistory>();

            // Lấy tất cả giao dịch trong khoảng thời gian để tính DailyBalanceHistory
            var allTransactions = await query
                .OrderBy(t => t.CreatedTime.Value)
                .ToListAsync();

            if (allTransactions.Any())
            {
                // Lấy ví để tính số dư ban đầu
                var wallet = await _walletRepository.Query()
                    .FirstOrDefaultAsync(w => w.Id == targetWalletId.Value);

                // Tính số dư ban đầu (số dư hiện tại - tổng thay đổi trong khoảng thời gian)
                var totalChange = allTransactions.Sum(t => t.TransactionDirection == TransactionDirection.Income ? t.Amount : -t.Amount);
                var initialBalance = (wallet?.Balance ?? 0) - totalChange;

                // Nhóm giao dịch theo ngày
                var dailyGroups = allTransactions
                    .GroupBy(t => t.CreatedTime.Value.DateTime.Date)
                    .OrderBy(g => g.Key)
                    .ToList();

                decimal runningBalance = initialBalance;

                foreach (var dayGroup in dailyGroups)
                {
                    var dayTransactions = dayGroup.OrderBy(t => t.CreatedTime.Value).ToList();
                    var startOfDayBalance = runningBalance;

                    // Tính số dư cuối ngày
                    foreach (var transaction in dayTransactions)
                    {
                        runningBalance += transaction.TransactionDirection == TransactionDirection.Income ? transaction.Amount : -transaction.Amount;
                    }

                    var endOfDayBalance = runningBalance;
                    var dailyChange = endOfDayBalance - startOfDayBalance;

                    dailyBalanceHistory.Add(new DailyBalanceHistory
                    {
                        Date = dayGroup.Key,
                        FormattedDate = dayGroup.Key.ToString("dd/MM/yyyy"),
                        StartOfDayBalance = startOfDayBalance,
                        EndOfDayBalance = endOfDayBalance,
                        DailyChange = dailyChange,
                        FormattedStartBalance = $"{startOfDayBalance:N0} VND",
                        FormattedEndBalance = $"{endOfDayBalance:N0} VND",
                        FormattedDailyChange = dailyChange >= 0
                            ? $"+{dailyChange:N0} VND"
                            : $"{dailyChange:N0} VND",
                        ChangeColor = dailyChange >= 0 ? "green" : "red"
                    });
                }
            }

            // Include thêm thông tin cần thiết cho mapping
            query = query
                .Include(t => t.Wallet)
                    .ThenInclude(w => w.User)
                .Include(t => t.RelatedWallet)
                    .ThenInclude(w => w.User)
                .Include(t => t.TransactionOrders)
                    .ThenInclude(to => to.Order);

            // Sử dụng ToSmartTableResultAsync như pattern cũ
            var gridData = await query.ToSmartTableResultAsync(param, x => x.ToItem());

            // Tạo kết quả mới với thông tin tổng thu và tổng chi
            return new TransactionSearchResult
            {
                Items = gridData.Items,
                TotalRecord = gridData.TotalRecord,
                NumberOfPages = gridData.NumberOfPages,
                From = gridData.From,
                To = gridData.To,
                LastPage = gridData.LastPage,
                TotalIncome = totalIncome,
                TotalOutcome = totalOutcome,
                TotalCash = totalCash,
                TotalTransfer = totalTransfer,
                DailyBalanceHistory = dailyBalanceHistory
            };
        }

        /// <summary>
        /// Lấy chi tiết giao dịch (chỉ cho TransactionType = 4)
        /// </summary>
        public async Task<TransactionDetailResult> GetTransactionDetail(Guid transactionId)
        {
            var result = new TransactionDetailResult();

            try
            {
                var transaction = await _transactionRepository.Query()
                    .Include(t => t.Wallet)
                        .ThenInclude(w => w.User)
                    .Include(t => t.RelatedWallet)
                        .ThenInclude(w => w.User)
                    .Include(t => t.TransactionOrders)
                        .ThenInclude(to => to.Order)
                            .ThenInclude(o => o.Customer)
                    .Include(t => t.TransactionOrders)
                        .ThenInclude(to => to.Order)
                            .ThenInclude(o => o.OrderFin)
                    .Include(t => t.TransactionOrders)
                        .ThenInclude(to => to.Order)
                            .ThenInclude(o => o.Addresses)
                    .FirstOrDefaultAsync(t => t.Id == transactionId);

                if (transaction == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy giao dịch";
                    return result;
                }

                // Chỉ cho phép xem chi tiết giao dịch có TransactionType = 4
                if (transaction.TransactionType != TransactionType.CollectFromDriver)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không có quyền xem chi tiết giao dịch này";
                    return result;
                }

                result.Transaction = transaction.ToItem();

                // Lấy thông tin đơn hàng liên quan
                var orders = new List<TransactionOrderItem>();
                foreach (var to in transaction.TransactionOrders)
                {
                    var item = new TransactionOrderItem
                    {
                        TransactionId = to.TransactionId,
                        OrderId = to.OrderId,
                        OrderCode = to.Order?.Code ?? "",
                        PartnerCode = to.Order?.PartnerCode ?? "",
                        OrderNote = to.Order?.Note ?? "",
                        CodAmount = to.CodAmount,
                        SourceFeeAmount = to.SourceFeeAmount,
                        DestFeeAmount = to.DestFeeAmount,
                        CustomerId = to.Order?.CustomerId ?? 0,
                        CustomerName = to.Order?.Customer?.FullName ?? "",
                        ChargeWeight = to.Order?.OrderFin?.ChargeWeight ?? 0,
                        OrderCodAmount = to.Order?.OrderFin?.CollectAmount ?? 0,
                        OrderFee = to.Order?.OrderFin?.Fee ?? 0,
                        OrderTotalFee = to.Order?.OrderFin?.TotalFee ?? 0,
                        PayFeeType = to.Order?.OrderFin?.PayFeeType ?? Lada.Framework.Data.Enums.OrderFinEnum.PayFeeType.SenderPay,
                        PayFeeTypeName = (to.Order?.OrderFin?.PayFeeType ?? Lada.Framework.Data.Enums.OrderFinEnum.PayFeeType.SenderPay).GetDescription(),
                        OrderCreatedTime = to.Order?.CreatedTime ?? DateTimeOffset.MinValue,
                        OrderUpdatedTime = to.Order?.UpdatedTime ?? DateTimeOffset.MinValue
                    };

                    // Lấy địa chỉ nguồn và đích
                    var sourceAddress = to.Order?.Addresses?.FirstOrDefault(a => a.AddressType == AddressType.Source);
                    var destAddress = to.Order?.Addresses?.FirstOrDefault(a => a.AddressType == AddressType.Dest);

                    if (sourceAddress != null)
                    {
                        item.SenderName = sourceAddress.Name ?? "";
                        item.SenderAddress = sourceAddress.Address1 ?? "";
                        item.SenderPhone = sourceAddress.PhoneNumber1 ?? "";
                    }

                    if (destAddress != null)
                    {
                        item.ReceiverName = destAddress.Name ?? "";
                        item.ReceiverAddress = destAddress.Address1 ?? "";
                        item.ReceiverPhone = destAddress.PhoneNumber1 ?? "";
                    }

                    orders.Add(item);
                }

                result.Orders = orders;

                // Thông tin ví nguồn
                if (transaction.Wallet != null)
                {
                    result.SourceWallet = new WalletInfo
                    {
                        Id = transaction.Wallet.Id,
                        OwnerName = transaction.Wallet.User?.UserName ?? "Unknown",
                        WalletType = transaction.Wallet.WalletType.GetDescription(),
                        Balance = transaction.Wallet.Balance,
                        Status = transaction.Wallet.WalletStatus.GetDescription()
                    };
                }

                // Thông tin ví đích
                if (transaction.RelatedWallet != null)
                {
                    result.DestinationWallet = new WalletInfo
                    {
                        Id = transaction.RelatedWallet.Id,
                        OwnerName = transaction.RelatedWallet.User?.UserName ?? "Unknown",
                        WalletType = transaction.RelatedWallet.WalletType.GetDescription(),
                        Balance = transaction.RelatedWallet.Balance,
                        Status = transaction.RelatedWallet.WalletStatus.GetDescription()
                    };
                }

                result.Result = Result.Success;
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = ex.Message;
            }

            return result;
        }

        /// <summary>
        /// Lấy thống kê giao dịch theo loại
        /// </summary>
        public async Task<TransactionStatisticsResult> GetTransactionStatistics(int walletId, DateTimeOffset? startDate = null, DateTimeOffset? endDate = null)
        {
            var result = new TransactionStatisticsResult();

            try
            {
                // Chỉ filter theo WalletId để tránh double-count khi có 2 dòng transaction cho transfer
                var query = _transactionRepository.Query()
                    .Where(t => t.WalletId == walletId);

                // Filter theo ngày nếu có
                if (startDate.HasValue && endDate.HasValue)
                {
                    var start = startDate.Value.StartOfDay();
                    var end = endDate.Value.EndOfDay();
                    query = query.Where(t => t.CreatedTime.HasValue && t.CreatedTime.Value >= start && t.CreatedTime.Value <= end);
                }

                var transactions = await query.ToListAsync();

                // Tính tổng số giao dịch
                result.TotalTransactions = transactions.Count;

                // Tính tổng thu/chi
                result.TotalIncome = transactions.Where(t => t.TransactionDirection == TransactionDirection.Income).Sum(t => t.Amount);
                result.TotalOutcome = transactions.Where(t => t.TransactionDirection == TransactionDirection.Outcome).Sum(t => t.Amount);

                // Tính tổng tiền mặt và chuyển khoản
                result.TotalCash = transactions.Sum(t => t.CashAmount);
                result.TotalTransfer = transactions.Sum(t => t.TransferAmount);

                // Tính tổng COD và cước phí từ TransactionOrders
                var transactionOrders = transactions.SelectMany(t => t.TransactionOrders ?? new List<TransactionOrder>());
                result.TotalCod = transactionOrders.Sum(to => to.CodAmount);
                result.TotalSourceFee = transactionOrders.Sum(to => to.SourceFeeAmount);
                result.TotalDestFee = transactionOrders.Sum(to => to.DestFeeAmount);

                // Thống kê theo loại giao dịch
                var typeStats = transactions
                    .GroupBy(t => t.TransactionType)
                    .Select(g => new TransactionTypeStatistic
                    {
                        TransactionType = g.Key.GetDescription(),
                        Count = g.Count(),
                        TotalAmount = g.Sum(t => t.Amount)
                    })
                    .OrderByDescending(s => s.Count)
                    .ToList();

                result.TypeStatistics = typeStats;

                // Thống kê theo ngày (7 ngày gần nhất)
                var dailyStats = transactions
                    .GroupBy(t => DateOnly.FromDateTime(t.CreatedTime.Value.DateTime))
                    .Select(g => new DailyTransactionStatistic
                    {
                        Date = g.Key,
                        TransactionCount = g.Count(),
                        TotalIncome = g.Where(t => t.TransactionDirection == TransactionDirection.Income).Sum(t => t.Amount),
                        TotalOutcome = g.Where(t => t.TransactionDirection == TransactionDirection.Outcome).Sum(t => t.Amount),
                        EndOfDayBalance = 0 // Sẽ tính sau nếu cần
                    })
                    .OrderByDescending(d => d.Date)
                    .Take(7)
                    .ToList();

                result.DailyStatistics = dailyStats;

                result.Result = Result.Success;
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = ex.Message;
            }

            return result;
        }

        /// <summary>
        /// Lấy lịch sử số dư ví
        /// </summary>
        public async Task<WalletBalanceHistoryResult> GetWalletBalanceHistory(int walletId, DateTimeOffset? startDate = null, DateTimeOffset? endDate = null)
        {
            var result = new WalletBalanceHistoryResult();

            try
            {
                // Lấy thông tin ví
                var wallet = await _walletRepository.Query()
                    .Include(w => w.User)
                    .FirstOrDefaultAsync(w => w.Id == walletId);

                if (wallet == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Không tìm thấy ví";
                    return result;
                }

                result.WalletId = walletId;
                result.WalletOwnerName = wallet.User?.FullName ?? wallet.User?.UserName ?? "Unknown";
                result.CurrentBalance = wallet.Balance;

                // Chỉ filter theo WalletId để tránh double-count khi có 2 dòng transaction cho transfer
                var query = _transactionRepository.Query()
                    .Where(t => t.WalletId == walletId);

                // Filter theo ngày nếu có
                if (startDate.HasValue && endDate.HasValue)
                {
                    var start = startDate.Value.StartOfDay();
                    var end = endDate.Value.EndOfDay();
                    query = query.Where(t => t.CreatedTime.HasValue && t.CreatedTime.Value >= start && t.CreatedTime.Value <= end);
                }

                query = query.OrderBy(t => t.CreatedTime.Value);

                var transactions = await query.ToListAsync();

                // Tính số dư ban đầu (số dư hiện tại - tổng thay đổi)
                var totalChange = transactions.Sum(t => t.TransactionDirection == TransactionDirection.Income ? t.Amount : -t.Amount);
                result.InitialBalance = result.CurrentBalance - totalChange;

                result.FormattedInitialBalance = $"{result.InitialBalance:N0} VND";
                result.FormattedCurrentBalance = $"{result.CurrentBalance:N0} VND";

                // Lịch sử theo giao dịch
                decimal runningBalance = result.InitialBalance;
                var transactionHistory = new List<TransactionBalanceHistory>();

                foreach (var transaction in transactions)
                {
                    runningBalance += transaction.TransactionDirection == TransactionDirection.Income ? transaction.Amount : -transaction.Amount;

                    transactionHistory.Add(new TransactionBalanceHistory
                    {
                        TransactionId = transaction.Id,
                        Description = transaction.Description,
                        TransactionTypeName = transaction.TransactionType.GetDescription(),
                        TransactionDirectionName = transaction.TransactionDirection.GetDescription(),
                        Amount = transaction.Amount,
                        FormattedAmount = transaction.TransactionDirection == TransactionDirection.Income
                            ? $"+{transaction.Amount:N0} VND"
                            : $"-{transaction.Amount:N0} VND",
                        BalanceAfterTransaction = runningBalance,
                        FormattedBalance = $"{runningBalance:N0} VND",
                        TransactionDate = transaction.CreatedTime.Value,
                        FormattedTransactionDate = transaction.CreatedTime.Value.ToString("dd/MM/yyyy HH:mm"),
                        AmountColor = transaction.TransactionDirection == TransactionDirection.Income ? "green" : "red",
                        TransactionIcon = GetTransactionIcon(transaction.TransactionType)
                    });
                }

                result.TransactionBalanceHistory = transactionHistory;

                // Lịch sử theo ngày
                var dailyHistory = transactions
                    .GroupBy(t => t.CreatedTime.Value.DateTime.Date)
                    .Select(g => new DailyBalanceHistory
                    {
                        Date = g.Key,
                        FormattedDate = g.Key.ToString("dd/MM/yyyy"),
                        StartOfDayBalance = 0, // Sẽ tính sau
                        EndOfDayBalance = 0, // Sẽ tính sau
                        DailyChange = g.Sum(t => t.TransactionDirection == TransactionDirection.Income ? t.Amount : -t.Amount),
                        FormattedDailyChange = g.Sum(t => t.TransactionDirection == TransactionDirection.Income ? t.Amount : -t.Amount) >= 0
                            ? $"+{g.Sum(t => t.TransactionDirection == TransactionDirection.Income ? t.Amount : -t.Amount):N0} VND"
                            : $"{g.Sum(t => t.TransactionDirection == TransactionDirection.Income ? t.Amount : -t.Amount):N0} VND",
                        ChangeColor = g.Sum(t => t.TransactionDirection == TransactionDirection.Income ? t.Amount : -t.Amount) >= 0 ? "green" : "red"
                    })
                    .OrderByDescending(d => d.Date)
                    .Take(30)
                    .ToList();

                result.DailyBalanceHistory = dailyHistory;

                result.Result = Result.Success;
            }
            catch (Exception ex)
            {
                result.Result = Result.Failed;
                result.Message = ex.Message;
            }

            return result;
        }

        /// <summary>
        /// Helper method để lấy icon cho loại giao dịch
        /// </summary>
        private string GetTransactionIcon(TransactionType transactionType)
        {
            return transactionType switch
            {
                TransactionType.Recharge => "💰",
                TransactionType.Withdraw => "💸",
                TransactionType.OrderFee => "📦",
                TransactionType.CollectFromDriver => "🚛",
                TransactionType.Reconciliation => "📊",
                TransactionType.CollectFromCustomer => "👤",
                TransactionType.Transfer => "🔄",
                _ => "💳"
            };
        }
    }
}