using System; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using LittleShop.Services; namespace LittleShop.Areas.Admin.Controllers; [Area("Admin")] [Authorize(Policy = "AdminOnly")] public class BotRecoveryController : Controller { private readonly IBotContactService _contactService; private readonly IBotService _botService; private readonly ILogger _logger; public BotRecoveryController( IBotContactService contactService, IBotService botService, ILogger logger) { _contactService = contactService; _botService = botService; _logger = logger; } // GET: Admin/BotRecovery public async Task Index() { var allBots = await _botService.GetAllBotsAsync(); var botsWithStatus = allBots.Select(bot => new { Bot = bot, Contacts = _contactService.GetBotContactsAsync(bot.Id).Result, IsHealthy = bot.Status == Enums.BotStatus.Active && bot.LastSeenAt > DateTime.UtcNow.AddMinutes(-5) }).ToList(); ViewData["BotsWithStatus"] = botsWithStatus; return View(); } // GET: Admin/BotRecovery/PrepareRecovery/{botId} public async Task PrepareRecovery(Guid botId) { var recoveryData = await _contactService.PrepareContactRecoveryAsync(botId); return View(recoveryData); } // POST: Admin/BotRecovery/ExecuteRecovery [HttpPost] [ValidateAntiForgeryToken] public async Task ExecuteRecovery(Guid fromBotId, Guid toBotId, bool notifyUsers = false) { try { // Migrate contacts var success = await _contactService.MigrateContactsAsync(fromBotId, toBotId); if (!success) { TempData["Error"] = "Failed to migrate contacts. Check logs for details."; return RedirectToAction(nameof(PrepareRecovery), new { botId = fromBotId }); } // Get the new bot info for notifications if (notifyUsers) { var toBot = await _botService.GetBotByIdAsync(toBotId); var orphanedContacts = await _contactService.GetOrphanedContactsAsync(fromBotId); foreach (var contact in orphanedContacts) { await _contactService.NotifyContactOfBotChangeAsync( contact.TelegramUserId, toBot.PlatformUsername); } } // Update bot statuses await _botService.UpdateBotStatusAsync(fromBotId, Enums.BotStatus.Deleted); TempData["Success"] = $"Successfully migrated contacts from bot {fromBotId} to {toBotId}"; return RedirectToAction(nameof(Index)); } catch (Exception ex) { _logger.LogError(ex, "Failed to execute bot recovery"); TempData["Error"] = "An error occurred during recovery. Please try again."; return RedirectToAction(nameof(PrepareRecovery), new { botId = fromBotId }); } } // GET: Admin/BotRecovery/Backup/{botId} public async Task Backup(Guid botId) { var backup = await _contactService.CreateContactBackupAsync(botId); // Return as downloadable JSON file var json = System.Text.Json.JsonSerializer.Serialize(backup, new System.Text.Json.JsonSerializerOptions { WriteIndented = true }); var bytes = System.Text.Encoding.UTF8.GetBytes(json); return File(bytes, "application/json", $"bot-contacts-{botId}-{DateTime.UtcNow:yyyyMMdd}.json"); } // POST: Admin/BotRecovery/RestoreBackup [HttpPost] [ValidateAntiForgeryToken] public async Task RestoreBackup(Guid toBotId, IFormFile backupFile) { if (backupFile == null || backupFile.Length == 0) { TempData["Error"] = "Please select a backup file to restore"; return RedirectToAction(nameof(Index)); } try { using var stream = backupFile.OpenReadStream(); using var reader = new System.IO.StreamReader(stream); var json = await reader.ReadToEndAsync(); var backup = System.Text.Json.JsonSerializer.Deserialize(json); if (backup == null) { TempData["Error"] = "Invalid backup file format"; return RedirectToAction(nameof(Index)); } var success = await _contactService.RestoreContactsFromBackupAsync(toBotId, backup); if (success) { TempData["Success"] = $"Successfully restored {backup.ContactCount} contacts to bot"; } else { TempData["Error"] = "Failed to restore contacts from backup"; } return RedirectToAction(nameof(Index)); } catch (Exception ex) { _logger.LogError(ex, "Failed to restore backup"); TempData["Error"] = "An error occurred while restoring the backup"; return RedirectToAction(nameof(Index)); } } // GET: Admin/BotRecovery/ContactHistory/{telegramUserId} public async Task ContactHistory(long telegramUserId) { // Show all bot interactions for a specific user ViewData["UserId"] = telegramUserId; // Implementation would query all BotContacts for this user across all bots return View(); } }