using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using SVSim.Database.Entities.Story; using SVSim.EmulatedEntrypoint.Models.Dtos.Story; using SVSim.EmulatedEntrypoint.Services; namespace SVSim.EmulatedEntrypoint.Controllers; [ApiController] [Authorize] public class StoryController : SVSimController { private readonly IStoryService _service; private readonly IMissionProgressService _missionProgress; public StoryController(IStoryService service, IMissionProgressService missionProgress) { _service = service; _missionProgress = missionProgress; } [HttpPost("/story/section")] [HttpPost("/main_story/section")] [HttpPost("/limited_story/section")] [HttpPost("/event_story/section")] public async Task> Section(SectionRequest req) { if (!TryGetViewerId(out long vid)) return Unauthorized(); return await _service.GetSectionsAsync(ResolveApiType(), vid); } [HttpPost("/main_story/leader_select")] [HttpPost("/limited_story/leader_select")] [HttpPost("/event_story/leader_select")] public async Task> LeaderSelect(LeaderSelectRequest req) { if (!TryGetViewerId(out long vid)) return Unauthorized(); return await _service.GetLeaderSelectAsync(ResolveApiType(), req.SectionId, vid); } [HttpPost("/main_story/info")] [HttpPost("/limited_story/info")] [HttpPost("/event_story/info")] public async Task> Info(InfoRequest req) { if (!TryGetViewerId(out long vid)) return Unauthorized(); int? chara = req.CharaId == 0 ? null : req.CharaId; return await _service.GetInfoAsync(ResolveApiType(), req.SectionId, chara, vid); } [HttpPost("/main_story/get_deck_list")] [HttpPost("/event_story/get_deck_list")] public async Task> GetDeckList(GetDeckListRequest req) { if (!TryGetViewerId(out long vid)) return Unauthorized(); return await _service.GetDeckListAsync(ResolveApiType(), req.StoryId, vid); } [HttpPost("/main_story/start")] [HttpPost("/limited_story/start")] [HttpPost("/event_story/start")] public async Task> Start(StartRequest req) { if (!TryGetViewerId(out long vid)) return Unauthorized(); return await _service.StartAsync(ResolveApiType(), req.StoryIds, vid); } [HttpPost("/main_story/finish")] [HttpPost("/limited_story/finish")] [HttpPost("/event_story/finish")] public async Task> Finish(FinishRequest req) { if (!TryGetViewerId(out long vid)) return Unauthorized(); var result = await _service.FinishAsync(ResolveApiType(), req, vid); // Emit story-chapter-finish events for mission/achievement progress. var apiType = ResolveApiType(); var prefix = apiType switch { StoryApiType.Main => "main", StoryApiType.Limited => "limited", StoryApiType.Event => "event", _ => null, }; if (prefix is not null && req.StoryId != 0) { await _missionProgress.RecordEventAsync(vid, new[] { "story_chapter_finish", $"story_chapter_finish:{prefix}", $"story_chapter_finish:{prefix}:{req.StoryId}", }); } return result; } [HttpPost("/main_story/all_finish")] [HttpPost("/limited_story/all_finish")] [HttpPost("/event_story/all_finish")] public async Task> AllFinish(AllFinishRequest req) { if (!TryGetViewerId(out long vid)) return Unauthorized(); return await _service.AllFinishAsync(ResolveApiType(), req.StoryIds, req.IsFinish == 1, vid); } private StoryApiType ResolveApiType() { var path = HttpContext.Request.Path.Value ?? ""; if (path.StartsWith("/main_story")) return StoryApiType.Main; if (path.StartsWith("/limited_story")) return StoryApiType.Limited; if (path.StartsWith("/event_story")) return StoryApiType.Event; return StoryApiType.AllStory; // /story/section } }