using System; using System.Linq; using System.Text.Json; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using LittleShop.DTOs; using LittleShop.Enums; using LittleShop.Services; namespace LittleShop.Areas.Admin.Controllers; [Area("Admin")] [Authorize(Policy = "AdminOnly")] public class BotsController : Controller { private readonly IBotService _botService; private readonly IBotMetricsService _metricsService; private readonly ITelegramBotManagerService _telegramManager; private readonly ILogger _logger; public BotsController( IBotService botService, IBotMetricsService metricsService, ITelegramBotManagerService telegramManager, ILogger logger) { _botService = botService; _metricsService = metricsService; _telegramManager = telegramManager; _logger = logger; } // GET: Admin/Bots public async Task Index() { var bots = await _botService.GetAllBotsAsync(); return View(bots); } // GET: Admin/Bots/Details/5 public async Task Details(Guid id) { var bot = await _botService.GetBotByIdAsync(id); if (bot == null) return NotFound(); // Get metrics summary for the last 30 days var metricsSummary = await _metricsService.GetMetricsSummaryAsync(id, DateTime.UtcNow.AddDays(-30), DateTime.UtcNow); ViewData["MetricsSummary"] = metricsSummary; // Get active sessions var activeSessions = await _metricsService.GetBotSessionsAsync(id, activeOnly: true); ViewData["ActiveSessions"] = activeSessions; return View(bot); } // GET: Admin/Bots/Create public IActionResult Create() { return View(new BotRegistrationDto()); } // GET: Admin/Bots/Wizard public IActionResult Wizard() { return View(new BotWizardDto()); } // POST: Admin/Bots/Wizard [HttpPost] [ValidateAntiForgeryToken] public async Task Wizard(BotWizardDto dto) { _logger.LogInformation("Wizard POST received - BotName: '{BotName}', BotUsername: '{BotUsername}'", dto.BotName, dto.BotUsername); if (!ModelState.IsValid) { _logger.LogWarning("Validation failed"); foreach (var error in ModelState) { _logger.LogWarning("Field {Field}: {Errors}", error.Key, string.Join(", ", error.Value.Errors.Select(e => e.ErrorMessage))); } return View(dto); } // Auto-assign personality if not selected if (string.IsNullOrEmpty(dto.PersonalityName)) { var personalities = new[] { "Alan", "Dave", "Sarah", "Mike", "Emma", "Tom" }; var random = new Random(); dto.PersonalityName = personalities[random.Next(personalities.Length)]; } // Generate BotFather commands var commands = GenerateBotFatherCommands(dto); ViewData["BotFatherCommands"] = commands; ViewData["ShowCommands"] = true; _logger.LogInformation("Generated BotFather commands successfully for bot '{BotName}' with personality '{PersonalityName}'", dto.BotName, dto.PersonalityName); return View(dto); } // POST: Admin/Bots/CompleteWizard [HttpPost] [ValidateAntiForgeryToken] public async Task CompleteWizard(BotWizardDto dto) { if (string.IsNullOrEmpty(dto.BotToken)) { ModelState.AddModelError("BotToken", "Bot token is required"); ViewData["BotFatherCommands"] = GenerateBotFatherCommands(dto); ViewData["ShowCommands"] = true; return View("Wizard", dto); } // Validate token first if (!await ValidateTelegramToken(dto.BotToken)) { ModelState.AddModelError("BotToken", "Invalid bot token"); ViewData["BotFatherCommands"] = GenerateBotFatherCommands(dto); ViewData["ShowCommands"] = true; return View("Wizard", dto); } // Create the bot var registrationDto = new BotRegistrationDto { Name = dto.BotName, Description = dto.Description, Type = BotType.Telegram, Version = "1.0.0", PersonalityName = dto.PersonalityName, InitialSettings = new Dictionary { ["telegram"] = new { botToken = dto.BotToken }, ["personality"] = new { name = dto.PersonalityName } } }; try { var result = await _botService.RegisterBotAsync(registrationDto); // Add bot to Telegram manager var telegramAdded = await _telegramManager.AddBotAsync(result.BotId, dto.BotToken); if (telegramAdded) { TempData["Success"] = $"Bot '{result.Name}' created successfully and is now running on Telegram!"; } else { TempData["Warning"] = $"Bot '{result.Name}' created but failed to connect to Telegram. Check token."; } return RedirectToAction(nameof(Details), new { id = result.BotId }); } catch (Exception ex) { _logger.LogError(ex, "Failed to create bot"); ModelState.AddModelError("", $"Failed to create bot: {ex.Message}"); return View("Wizard", dto); } } // POST: Admin/Bots/Create [HttpPost] [ValidateAntiForgeryToken] public async Task Create(BotRegistrationDto dto) { _logger.LogInformation("Received bot registration: Name={Name}, Type={Type}, Version={Version}", dto?.Name, dto?.Type, dto?.Version); if (!ModelState.IsValid) { _logger.LogWarning("Model validation failed for bot registration"); foreach (var error in ModelState.Values.SelectMany(v => v.Errors)) { _logger.LogWarning("Validation error: {Error}", error.ErrorMessage); } return View(dto); } try { var result = await _botService.RegisterBotAsync(dto); _logger.LogInformation("Bot registered successfully: {BotId}, Key: {KeyPrefix}...", result.BotId, result.BotKey.Substring(0, 8)); TempData["BotKey"] = result.BotKey; TempData["Success"] = $"Bot '{result.Name}' created successfully. Save the API key securely!"; return RedirectToAction(nameof(Details), new { id = result.BotId }); } catch (Exception ex) { _logger.LogError(ex, "Failed to create bot"); ModelState.AddModelError("", $"Failed to create bot: {ex.Message}"); return View(dto); } } // GET: Admin/Bots/Edit/5 public async Task Edit(Guid id) { var bot = await _botService.GetBotByIdAsync(id); if (bot == null) return NotFound(); ViewData["BotSettings"] = JsonSerializer.Serialize(bot.Settings, new JsonSerializerOptions { WriteIndented = true }); return View(bot); } // POST: Admin/Bots/Edit/5 [HttpPost] [ValidateAntiForgeryToken] public async Task Edit(Guid id, string settingsJson, BotStatus status) { try { // Parse and update settings var settings = JsonSerializer.Deserialize>(settingsJson) ?? new Dictionary(); var updateDto = new UpdateBotSettingsDto { Settings = settings }; await _botService.UpdateBotSettingsAsync(id, updateDto); await _botService.UpdateBotStatusAsync(id, status); TempData["Success"] = "Bot updated successfully"; return RedirectToAction(nameof(Details), new { id }); } catch (Exception ex) { _logger.LogError(ex, "Failed to update bot"); TempData["Error"] = "Failed to update bot"; return RedirectToAction(nameof(Edit), new { id }); } } // GET: Admin/Bots/Metrics/5 public async Task Metrics(Guid id, DateTime? startDate, DateTime? endDate) { var bot = await _botService.GetBotByIdAsync(id); if (bot == null) return NotFound(); var start = startDate ?? DateTime.UtcNow.AddDays(-7); var end = endDate ?? DateTime.UtcNow; var metricsSummary = await _metricsService.GetMetricsSummaryAsync(id, start, end); var sessionSummary = await _metricsService.GetSessionSummaryAsync(id, start, end); ViewData["Bot"] = bot; ViewData["SessionSummary"] = sessionSummary; ViewData["StartDate"] = start; ViewData["EndDate"] = end; return View(metricsSummary); } // POST: Admin/Bots/Delete/5 [HttpPost] [ValidateAntiForgeryToken] public async Task Delete(Guid id) { var success = await _botService.DeleteBotAsync(id); if (!success) { TempData["Error"] = "Failed to delete bot"; return RedirectToAction(nameof(Index)); } TempData["Success"] = "Bot deleted successfully"; return RedirectToAction(nameof(Index)); } // POST: Admin/Bots/Suspend/5 [HttpPost] [ValidateAntiForgeryToken] public async Task Suspend(Guid id) { await _botService.UpdateBotStatusAsync(id, BotStatus.Suspended); TempData["Success"] = "Bot suspended"; return RedirectToAction(nameof(Details), new { id }); } // POST: Admin/Bots/Activate/5 [HttpPost] [ValidateAntiForgeryToken] public async Task Activate(Guid id) { await _botService.UpdateBotStatusAsync(id, BotStatus.Active); TempData["Success"] = "Bot activated"; return RedirectToAction(nameof(Details), new { id }); } // POST: Admin/Bots/UpdateWallets/5 [HttpPost] [ValidateAntiForgeryToken] public async Task UpdateWallets(Guid id, Dictionary wallets) { try { var bot = await _botService.GetBotByIdAsync(id); if (bot == null) { TempData["Error"] = "Bot not found"; return RedirectToAction(nameof(Index)); } // Get current settings var settings = bot.Settings ?? new Dictionary(); // Filter out empty wallet addresses var validWallets = wallets .Where(w => !string.IsNullOrWhiteSpace(w.Value)) .ToDictionary(w => w.Key, w => w.Value.Trim()); // Update or add wallets section settings["wallets"] = validWallets; // Save settings await _botService.UpdateBotSettingsAsync(id, new UpdateBotSettingsDto { Settings = settings }); _logger.LogInformation("Updated {Count} wallet addresses for bot {BotId}", validWallets.Count, id); TempData["Success"] = $"Updated {validWallets.Count} wallet address(es) successfully"; return RedirectToAction(nameof(Edit), new { id }); } catch (Exception ex) { _logger.LogError(ex, "Failed to update wallets for bot {BotId}", id); TempData["Error"] = "Failed to update wallet addresses"; return RedirectToAction(nameof(Edit), new { id }); } } // GET: Admin/Bots/RegenerateKey/5 public IActionResult RegenerateKey(Guid id) { // This would require updating the bot model to support key regeneration TempData["Error"] = "Key regeneration not yet implemented"; return RedirectToAction(nameof(Details), new { id }); } private string GenerateBotFatherCommands(BotWizardDto dto) { var commands = new List { "1. Open Telegram and find @BotFather", "2. Send: /newbot", $"3. Send bot name: {dto.BotName}", $"4. Send bot username: {dto.BotUsername}", "5. Copy the token from BotFather's response", "6. Paste the token in the field below" }; if (!string.IsNullOrEmpty(dto.Description)) { commands.Add($"7. Optional: Send /setdescription and then: {dto.Description}"); } return string.Join("\n", commands); } private async Task ValidateTelegramToken(string token) { try { using var httpClient = new HttpClient(); var response = await httpClient.GetAsync($"https://api.telegram.org/bot{token}/getMe"); return response.IsSuccessStatusCode; } catch { return false; } } }