using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using PlotLine.Services; using PlotLine.ViewModels; namespace PlotLine.Controllers; [Authorize(Policy = "AdminOnly")] [Route("Development")] public sealed class DevelopmentController( IWebHostEnvironment environment, ICurrentUserService currentUser, IIllustrationLibraryService illustrationLibrary, IStoryIntelligenceVisualisationSnapshotService snapshots) : Controller { [HttpGet("StoryIntelligenceExperience")] public async Task StoryIntelligenceExperience([FromQuery] string? mode, [FromQuery] int? importSessionId, [FromQuery] int? runId) { if (!environment.IsDevelopment()) { return NotFound(); } var requestedMode = string.IsNullOrWhiteSpace(mode) ? "real" : mode.Trim(); var simulationRequested = string.Equals(requestedMode, "simulation", StringComparison.OrdinalIgnoreCase); if (!simulationRequested && importSessionId.HasValue && currentUser.UserId is int userId) { var realModel = await snapshots.BuildImportSessionSnapshotAsync(importSessionId.Value, userId); if (realModel is null) { return View(ErrorModel( requestedMode, importSessionId, $"Import Session {importSessionId.Value:N0} could not be found for the current user, or it has no persisted chapter analysis runs yet.")); } return View(realModel); } if (!simulationRequested && runId.HasValue && currentUser.UserId is int legacyUserId) { var realModel = await snapshots.BuildSnapshotAsync(runId.Value, legacyUserId); if (realModel is null) { return View(ErrorModel( requestedMode, null, $"Run {runId.Value:N0} could not be found for the current user. Live visualisation URLs should use importSessionId for book imports.")); } return View(realModel); } if (simulationRequested) { var model = StoryIntelligenceExperiencePrototypeData.Build(); await illustrationLibrary.ApplyApprovedIllustrationsAsync(model); return View(model); } if (currentUser.UserId is int selectorUserId) { var sessions = await snapshots.ListImportSessionOptionsAsync(selectorUserId); return View(new StoryIntelligenceExperiencePrototypeViewModel { Mode = "selector", AvailableRuns = sessions, ProjectName = "Development", BookTitle = "Story Intelligence", SnapshotMessage = sessions.Count == 0 ? "No persisted Story Intelligence import sessions were found for the current user. Start a real import, then refresh this page." : "Choose a Story Intelligence import session, or explicitly open simulation mode.", Diagnostics = new StoryIntelligenceExperienceSnapshotDiagnostics { RequestedMode = requestedMode, RequestedImportSessionId = importSessionId, SnapshotSource = "Real" } }); } return View(ErrorModel(requestedMode, importSessionId, "No development user is signed in.")); } private static StoryIntelligenceExperiencePrototypeViewModel ErrorModel(string requestedMode, int? importSessionId, string message) => new() { Mode = "error", ProjectName = "Development", BookTitle = "Story Intelligence", SnapshotMessage = message, Diagnostics = new StoryIntelligenceExperienceSnapshotDiagnostics { RequestedMode = requestedMode, RequestedImportSessionId = importSessionId, SnapshotSource = "Real", Warning = message } }; }