littleshop/TeleBot/TeleBotClient/BotSimulator.cs
2025-08-27 18:02:39 +01:00

308 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bogus;
using LittleShop.Client;
using LittleShop.Client.Models;
using Microsoft.Extensions.Logging;
namespace TeleBotClient
{
public class BotSimulator
{
private readonly ILittleShopClient _client;
private readonly ILogger<BotSimulator> _logger;
private readonly Random _random;
private readonly Faker _faker;
private List<Category> _categories = new();
private List<Product> _products = new();
public BotSimulator(ILittleShopClient client, ILogger<BotSimulator> logger)
{
_client = client;
_logger = logger;
_random = new Random();
_faker = new Faker();
}
public async Task<SimulationResult> SimulateUserSession()
{
var result = new SimulationResult
{
SessionId = Guid.NewGuid().ToString(),
StartTime = DateTime.UtcNow
};
try
{
_logger.LogInformation("🤖 Starting bot simulation session {SessionId}", result.SessionId);
// Step 1: Authenticate
_logger.LogInformation("📝 Authenticating with API...");
if (!await Authenticate())
{
result.Success = false;
result.ErrorMessage = "Authentication failed";
return result;
}
result.Steps.Add("✅ Authentication successful");
// Step 2: Browse categories
_logger.LogInformation("📁 Browsing categories...");
await BrowseCategories();
result.Steps.Add($"✅ Found {_categories.Count} categories");
// Step 3: Select random category and browse products
if (_categories.Any())
{
var selectedCategory = _categories[_random.Next(_categories.Count)];
_logger.LogInformation("🔍 Selected category: {Category}", selectedCategory.Name);
result.Steps.Add($"✅ Selected category: {selectedCategory.Name}");
await BrowseProducts(selectedCategory.Id);
result.Steps.Add($"✅ Found {_products.Count} products in category");
}
else
{
// Browse all products if no categories
await BrowseProducts(null);
result.Steps.Add($"✅ Found {_products.Count} total products");
}
// Step 4: Build shopping cart
_logger.LogInformation("🛒 Building shopping cart...");
var cart = BuildRandomCart();
result.Cart = cart;
result.Steps.Add($"✅ Added {cart.Items.Count} items to cart (Total: ${cart.TotalAmount:F2})");
// Step 5: Generate shipping information
_logger.LogInformation("📦 Generating shipping information...");
var shippingInfo = GenerateShippingInfo();
result.ShippingInfo = shippingInfo;
result.Steps.Add($"✅ Generated shipping to {shippingInfo.City}, {shippingInfo.Country}");
// Step 6: Create order
_logger.LogInformation("📝 Creating order...");
var order = await CreateOrder(cart, shippingInfo);
if (order != null)
{
result.OrderId = order.Id;
result.OrderTotal = order.TotalAmount;
result.Steps.Add($"✅ Order created: {order.Id}");
// Step 7: Select payment method
var currency = SelectRandomCurrency();
_logger.LogInformation("💰 Selected payment method: {Currency}", currency);
result.PaymentCurrency = currency;
result.Steps.Add($"✅ Selected payment: {currency}");
// Step 8: Create payment
var payment = await CreatePayment(order.Id, currency);
if (payment != null)
{
result.PaymentId = payment.Id;
result.PaymentAddress = payment.WalletAddress;
result.PaymentAmount = payment.RequiredAmount;
result.Steps.Add($"✅ Payment created: {payment.RequiredAmount} {currency}");
}
}
result.Success = true;
result.EndTime = DateTime.UtcNow;
result.Duration = result.EndTime - result.StartTime;
_logger.LogInformation("✅ Simulation completed successfully in {Duration}", result.Duration);
}
catch (Exception ex)
{
_logger.LogError(ex, "❌ Simulation failed");
result.Success = false;
result.ErrorMessage = ex.Message;
result.EndTime = DateTime.UtcNow;
result.Duration = result.EndTime - result.StartTime;
}
return result;
}
private async Task<bool> Authenticate()
{
var result = await _client.Authentication.LoginAsync("admin", "admin");
if (result.IsSuccess && result.Data != null && !string.IsNullOrEmpty(result.Data.Token))
{
_client.Authentication.SetToken(result.Data.Token);
return true;
}
return false;
}
private async Task BrowseCategories()
{
var result = await _client.Catalog.GetCategoriesAsync();
if (result.IsSuccess && result.Data != null)
{
_categories = result.Data;
}
}
private async Task BrowseProducts(Guid? categoryId)
{
var result = await _client.Catalog.GetProductsAsync(
pageNumber: 1,
pageSize: 50,
categoryId: categoryId
);
if (result.IsSuccess && result.Data != null)
{
_products = result.Data.Items;
}
}
private ShoppingCart BuildRandomCart()
{
var cart = new ShoppingCart();
if (!_products.Any())
return cart;
// Random number of items (1-5)
var itemCount = _random.Next(1, Math.Min(6, _products.Count + 1));
var selectedProducts = _products.OrderBy(x => _random.Next()).Take(itemCount).ToList();
foreach (var product in selectedProducts)
{
var quantity = _random.Next(1, 4); // 1-3 items
cart.AddItem(product.Id, product.Name, product.Price, quantity);
_logger.LogDebug("Added {Quantity}x {Product} @ ${Price}",
quantity, product.Name, product.Price);
}
return cart;
}
private ShippingInfo GenerateShippingInfo()
{
return new ShippingInfo
{
IdentityReference = $"SIM-{Guid.NewGuid().ToString().Substring(0, 8).ToUpper()}",
Name = _faker.Name.FullName(),
Address = _faker.Address.StreetAddress(),
City = _faker.Address.City(),
PostCode = _faker.Address.ZipCode(),
Country = _faker.PickRandom(new[] { "United Kingdom", "Ireland", "France", "Germany", "Netherlands" }),
Notes = _faker.Lorem.Sentence()
};
}
private async Task<Order?> CreateOrder(ShoppingCart cart, ShippingInfo shipping)
{
var request = new CreateOrderRequest
{
IdentityReference = shipping.IdentityReference,
ShippingName = shipping.Name,
ShippingAddress = shipping.Address,
ShippingCity = shipping.City,
ShippingPostCode = shipping.PostCode,
ShippingCountry = shipping.Country,
Notes = shipping.Notes,
Items = cart.Items.Select(i => new CreateOrderItem
{
ProductId = i.ProductId,
Quantity = i.Quantity
}).ToList()
};
var result = await _client.Orders.CreateOrderAsync(request);
return result.IsSuccess ? result.Data : null;
}
private string SelectRandomCurrency()
{
var currencies = new[] { "BTC", "XMR", "USDT", "LTC", "ETH", "ZEC", "DASH", "DOGE" };
// Weight towards BTC and XMR
var weights = new[] { 30, 25, 15, 10, 10, 5, 3, 2 };
var totalWeight = weights.Sum();
var randomValue = _random.Next(totalWeight);
var currentWeight = 0;
for (int i = 0; i < currencies.Length; i++)
{
currentWeight += weights[i];
if (randomValue < currentWeight)
return currencies[i];
}
return "BTC";
}
private async Task<CryptoPayment?> CreatePayment(Guid orderId, string currency)
{
var result = await _client.Orders.CreatePaymentAsync(orderId, currency);
return result.IsSuccess ? result.Data : null;
}
}
public class SimulationResult
{
public string SessionId { get; set; } = string.Empty;
public bool Success { get; set; }
public string? ErrorMessage { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan Duration { get; set; }
public List<string> Steps { get; set; } = new();
// Order details
public Guid? OrderId { get; set; }
public decimal OrderTotal { get; set; }
public ShoppingCart? Cart { get; set; }
public ShippingInfo? ShippingInfo { get; set; }
// Payment details
public Guid? PaymentId { get; set; }
public string? PaymentCurrency { get; set; }
public string? PaymentAddress { get; set; }
public decimal PaymentAmount { get; set; }
}
public class ShoppingCart
{
public List<CartItem> Items { get; set; } = new();
public decimal TotalAmount => Items.Sum(i => i.TotalPrice);
public void AddItem(Guid productId, string name, decimal price, int quantity)
{
Items.Add(new CartItem
{
ProductId = productId,
ProductName = name,
UnitPrice = price,
Quantity = quantity,
TotalPrice = price * quantity
});
}
}
public class CartItem
{
public Guid ProductId { get; set; }
public string ProductName { get; set; } = string.Empty;
public decimal UnitPrice { get; set; }
public int Quantity { get; set; }
public decimal TotalPrice { get; set; }
}
public class ShippingInfo
{
public string IdentityReference { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
public string PostCode { get; set; } = string.Empty;
public string Country { get; set; } = string.Empty;
public string? Notes { get; set; }
}
}