using Lada.Framework.Data.Domains;
using Lada.Framework.Data.Domains.Finance.Wallets;
using Lada.Framework.Data.Domains.Medias;
using Lada.Framework.Data.Enums;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.Infrastructures.Helpers;
using Lada.Framework.Infrastructures.Services;
using Ladaer.BackEnd.Infrastructures.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Finances;
using Microsoft.EntityFrameworkCore;

namespace Ladaer.BackEnd.Infrastructures.Services.Finances
{
    /// <summary>
    /// Interface cho service chuyển tiền giữa các ví
    /// </summary>
    public interface IWalletTransferService
    {
        /// <summary>
        /// Chuyển tiền từ ví nguồn sang ví đích
        /// </summary>
        /// <param name="sourceWalletId">ID ví nguồn (ví của người dùng đang đăng nhập)</param>
        /// <param name="model">Thông tin chuyển tiền</param>
        /// <returns>Kết quả chuyển tiền</returns>
        Task<WalletTransferResult> Transfer(int sourceWalletId, TransferWalletModel model);
    }

    /// <summary>
    /// Service xử lý chuyển tiền giữa các ví với đảm bảo toàn vẹn giao dịch
    /// Sử dụng DB Transaction + Optimistic Concurrency (RowVersion)
    /// </summary>
    public class WalletTransferService : IWalletTransferService
    {
        private readonly IRepository<Wallet> _walletRepository;
        private readonly IRepository<Transaction> _transactionRepository;
        private readonly IRepository<Media> _mediaRepository;
        private readonly IUnifiedMediaService _unifiedMediaService;
        private const int MaxRetryAttempts = 3;
        private const int RetryDelayMs = 100;

        public WalletTransferService(
            IRepository<Wallet> walletRepository,
            IRepository<Transaction> transactionRepository,
            IRepository<Media> mediaRepository,
            IUnifiedMediaService unifiedMediaService)
        {
            _walletRepository = walletRepository;
            _transactionRepository = transactionRepository;
            _mediaRepository = mediaRepository;
            _unifiedMediaService = unifiedMediaService;
        }

        /// <summary>
        /// Chuyển tiền từ ví nguồn sang ví đích với đảm bảo toàn vẹn
        /// </summary>
        /// <param name="sourceWalletId">ID ví nguồn (ví của người dùng đang đăng nhập)</param>
        /// <param name="model">Thông tin chuyển tiền</param>
        public async Task<WalletTransferResult> Transfer(int sourceWalletId, TransferWalletModel model)
        {
            var result = new WalletTransferResult();

            // Validate input
            var validationResult = ValidateTransferRequest(sourceWalletId, model);
            if (!validationResult.IsValid)
            {
                result.Result = Result.Failed;
                result.Message = validationResult.ErrorMessage;
                return result;
            }

            // Tạo TransferGroupId (dùng RequestId nếu có để đảm bảo idempotency)
            var transferGroupId = model.RequestId ?? Guid.NewGuid();

            // Kiểm tra idempotency - nếu đã có giao dịch với TransferGroupId này thì không tạo lại
            var existingTransfer = await _transactionRepository.Query()
                .AnyAsync(t => t.TransferGroupId == transferGroupId);

            if (existingTransfer)
            {
                result.Result = Result.Failed;
                result.Message = "Giao dịch chuyển tiền này đã được thực hiện trước đó";
                return result;
            }

            // Retry loop để xử lý concurrency conflicts
            for (int attempt = 1; attempt <= MaxRetryAttempts; attempt++)
            {
                try
                {
                    var transferResult = await ExecuteTransferAsync(sourceWalletId, model, transferGroupId);
                    return transferResult;
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (attempt == MaxRetryAttempts)
                    {
                        result.Result = Result.Failed;
                        result.Message = "Giao dịch bị xung đột do có người khác đang thao tác. Vui lòng thử lại sau.";
                        return result;
                    }

                    // Wait before retry với exponential backoff
                    await Task.Delay(RetryDelayMs * attempt);
                }
                catch (Exception ex)
                {
                    result.Result = Result.SystemError;
                    result.Message = $"Lỗi hệ thống: {ex.Message}";
                    return result;
                }
            }

            return result;
        }

        /// <summary>
        /// Thực hiện giao dịch chuyển tiền trong DB Transaction
        /// </summary>
        /// <param name="sourceWalletId">ID ví nguồn</param>
        /// <param name="model">Thông tin chuyển tiền</param>
        /// <param name="transferGroupId">ID nhóm giao dịch</param>
        private async Task<WalletTransferResult> ExecuteTransferAsync(int sourceWalletId, TransferWalletModel model, Guid transferGroupId)
        {
            var result = new WalletTransferResult();
            var currentTime = DateTimeHelper.CurrentTime();

            using var dbTransaction = _walletRepository.BeginTransaction();

            try
            {
                // Load 2 ví theo thứ tự ID (min -> max) để tránh deadlock
                var walletIds = new[] { sourceWalletId, model.DestinationWalletId }.OrderBy(x => x).ToArray();

                var wallets = await _walletRepository.Query()
                    .Where(w => walletIds.Contains(w.Id))
                    .Include(w => w.User)
                    .ToListAsync();

                var sourceWallet = wallets.FirstOrDefault(w => w.Id == sourceWalletId);
                var destWallet = wallets.FirstOrDefault(w => w.Id == model.DestinationWalletId);

                // Validate ví tồn tại
                if (sourceWallet == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Ví nguồn không tồn tại";
                    return result;
                }

                if (destWallet == null)
                {
                    result.Result = Result.Failed;
                    result.Message = "Ví đích không tồn tại";
                    return result;
                }

                // Validate ví đang hoạt động
                if (sourceWallet.WalletStatus != WalletStatus.Active)
                {
                    result.Result = Result.Failed;
                    result.Message = "Ví nguồn không ở trạng thái hoạt động";
                    return result;
                }

                if (destWallet.WalletStatus != WalletStatus.Active)
                {
                    result.Result = Result.Failed;
                    result.Message = "Ví đích không ở trạng thái hoạt động";
                    return result;
                }

                // Kiểm tra số dư
                if (sourceWallet.Balance < model.Amount)
                {
                    result.Result = Result.Failed;
                    result.Message = $"Số dư ví nguồn không đủ. Số dư hiện tại: {sourceWallet.Balance:N0} VND, cần: {model.Amount:N0} VND";
                    return result;
                }

                // Đảm bảo Note không null (để tránh lỗi SQL constraint)
                model.Note ??= string.Empty;

                // Tạo mô tả giao dịch
                var sourceUserName = sourceWallet.User?.FullName ?? sourceWallet.User?.UserName ?? $"Ví #{sourceWallet.Id}";
                var destUserName = destWallet.User?.FullName ?? destWallet.User?.UserName ?? $"Ví #{destWallet.Id}";

                // Validate và xử lý ảnh chứng từ
                var isValidImage = await _unifiedMediaService.ValidateImageAsync(model.ProofImage);
                if (!isValidImage)
                {
                    result.Result = Result.Failed;
                    result.Message = "File tải lên không phải là ảnh hợp lệ";
                    return result;
                }

                var processResult = await _unifiedMediaService.ProcessImageAsync(model.ProofImage, ImageType.Document);
                if (processResult.Result != Result.Success)
                {
                    result.Result = Result.Failed;
                    result.Message = $"Lỗi khi xử lý ảnh: {processResult.Message}";
                    return result;
                }

                // Tạo Media entity
                var media = new Media
                {
                    Id = Guid.NewGuid(),
                    SystemPath = processResult.SystemPath,
                    AltText = $"Chứng từ chuyển tiền - {transferGroupId}",
                    Caption = $"Ảnh chứng từ chuyển tiền từ {sourceUserName} đến {destUserName}",
                    DisplayOrder = 1,
                    CreatedTime = currentTime,
                    UpdatedTime = currentTime,
                    CreatedBy = model.UpdatedBy,
                    CreatedByUserName = model.UpdatedByUserName,
                    UpdatedBy = model.UpdatedBy,
                    UpdatedByUserName = model.UpdatedByUserName
                };

                await _mediaRepository.InsertAsync(media);

                // Tạo Transaction cho ví nguồn (Outcome - trừ tiền)
                var sourceTransaction = new Transaction
                {
                    Id = Guid.NewGuid(),
                    Description = $"Chuyển tiền đến {destUserName}",
                    Note = model.Note,
                    Amount = model.Amount,
                    CashAmount = 0,
                    TransferAmount = model.Amount,
                    WalletId = sourceWallet.Id,
                    RelatedWalletId = destWallet.Id,
                    TransactionType = TransactionType.Transfer,
                    TransactionDirection = TransactionDirection.Outcome,
                    TransactionDate = currentTime,
                    FromUserId = model.UpdatedBy,
                    TransferGroupId = transferGroupId,
                    MediaId = media.Id,
                    CreatedTime = currentTime,
                    UpdatedTime = currentTime,
                    CreatedBy = model.UpdatedBy,
                    CreatedByUserName = model.UpdatedByUserName,
                    UpdatedBy = model.UpdatedBy,
                    UpdatedByUserName = model.UpdatedByUserName,
                    IsDeleted = false
                };

                // Tạo Transaction cho ví đích (Income - cộng tiền)
                var destTransaction = new Transaction
                {
                    Id = Guid.NewGuid(),
                    Description = $"Nhận tiền từ {sourceUserName}",
                    Note = model.Note,
                    Amount = model.Amount,
                    CashAmount = 0,
                    TransferAmount = model.Amount,
                    WalletId = destWallet.Id,
                    RelatedWalletId = sourceWallet.Id,
                    TransactionType = TransactionType.Transfer,
                    TransactionDirection = TransactionDirection.Income,
                    TransactionDate = currentTime,
                    FromUserId = model.UpdatedBy,
                    TransferGroupId = transferGroupId,
                    MediaId = media.Id,
                    CreatedTime = currentTime,
                    UpdatedTime = currentTime,
                    CreatedBy = model.UpdatedBy,
                    CreatedByUserName = model.UpdatedByUserName,
                    UpdatedBy = model.UpdatedBy,
                    UpdatedByUserName = model.UpdatedByUserName,
                    IsDeleted = false
                };

                // Insert 2 transactions
                await _transactionRepository.InsertAsync(sourceTransaction);
                await _transactionRepository.InsertAsync(destTransaction);

                // Cập nhật số dư ví nguồn (trừ tiền)
                sourceWallet.Balance -= model.Amount;
                sourceWallet.UpdatedTime = currentTime;
                sourceWallet.UpdatedBy = model.UpdatedBy;
                sourceWallet.UpdatedByUserName = model.UpdatedByUserName;
                await _walletRepository.UpdateAsync(sourceWallet);

                // Cập nhật số dư ví đích (cộng tiền)
                destWallet.Balance += model.Amount;
                destWallet.UpdatedTime = currentTime;
                destWallet.UpdatedBy = model.UpdatedBy;
                destWallet.UpdatedByUserName = model.UpdatedByUserName;
                await _walletRepository.UpdateAsync(destWallet);

                // Commit transaction
                await dbTransaction.CommitAsync();

                // Populate result
                result.Result = Result.Success;
                result.Message = $"Chuyển tiền thành công {model.Amount:N0} VND từ {sourceUserName} đến {destUserName}";
                result.TransferGroupId = transferGroupId;
                result.SourceTransactionId = sourceTransaction.Id;
                result.DestTransactionId = destTransaction.Id;
                result.SourceWalletNewBalance = sourceWallet.Balance;
                result.DestWalletNewBalance = destWallet.Balance;

                return result;
            }
            catch (DbUpdateConcurrencyException)
            {
                await dbTransaction.RollbackAsync();
                throw; // Rethrow để retry loop xử lý
            }
            catch (Exception ex)
            {
                await dbTransaction.RollbackAsync();
                result.Result = Result.SystemError;
                result.Message = $"Lỗi khi thực hiện chuyển tiền: {ex.Message}";
                return result;
            }
        }

        /// <summary>
        /// Validate yêu cầu chuyển tiền
        /// </summary>
        /// <param name="sourceWalletId">ID ví nguồn</param>
        /// <param name="model">Thông tin chuyển tiền</param>
        private ValidationResult ValidateTransferRequest(int sourceWalletId, TransferWalletModel model)
        {
            if (sourceWalletId <= 0)
                return ValidationResult.Fail("ID ví nguồn không hợp lệ");

            if (model.DestinationWalletId <= 0)
                return ValidationResult.Fail("ID ví đích không hợp lệ");

            if (sourceWalletId == model.DestinationWalletId)
                return ValidationResult.Fail("Ví nguồn và ví đích không được trùng nhau");

            if (model.Amount <= 0)
                return ValidationResult.Fail("Số tiền chuyển phải lớn hơn 0");

            if (model.UpdatedBy <= 0 || string.IsNullOrEmpty(model.UpdatedByUserName))
                return ValidationResult.Fail("Không xác định được người thực hiện giao dịch");

            if (model.ProofImage == null)
                return ValidationResult.Fail("Vui lòng upload ảnh chứng từ");

            return ValidationResult.Ok();
        }

        /// <summary>
        /// Kết quả validation
        /// </summary>
        private class ValidationResult
        {
            public bool IsValid { get; set; }
            public string ErrorMessage { get; set; } = string.Empty;

            public static ValidationResult Ok() => new() { IsValid = true };
            public static ValidationResult Fail(string message) => new() { IsValid = false, ErrorMessage = message };
        }
    }

    /// <summary>
    /// Kết quả chuyển tiền
    /// </summary>
    public class WalletTransferResult : BaseResult
    {
        /// <summary>
        /// ID nhóm giao dịch (dùng để tra cứu 2 dòng transaction)
        /// </summary>
        public Guid? TransferGroupId { get; set; }

        /// <summary>
        /// ID giao dịch bên ví nguồn
        /// </summary>
        public Guid? SourceTransactionId { get; set; }

        /// <summary>
        /// ID giao dịch bên ví đích
        /// </summary>
        public Guid? DestTransactionId { get; set; }

        /// <summary>
        /// Số dư mới của ví nguồn sau khi chuyển
        /// </summary>
        public decimal? SourceWalletNewBalance { get; set; }

        /// <summary>
        /// Số dư mới của ví đích sau khi chuyển
        /// </summary>
        public decimal? DestWalletNewBalance { get; set; }
    }
}

