using System.Globalization; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using PlotLine.Services; namespace PlotLine.Controllers; [Authorize] public sealed class StoryCalendarController(IStoryCalendarService calendar) : Controller { public async Task Index(int projectId, int? bookId, string? month, string? date) { if (projectId == 0) { return BadRequest("ProjectID is required."); } var selectedMonth = ParseMonth(month); var selectedDate = ParseDate(date); var model = await calendar.GetAsync(projectId, bookId, selectedMonth, selectedDate); return model is null ? NotFound() : View(model); } [HttpPost] [ValidateAntiForgeryToken] public IActionResult ApplyFilters(int projectId, int? bookId, string? month) { return RedirectToAction(nameof(Index), new { projectId, bookId, month }); } private static DateOnly? ParseMonth(string? value) { if (string.IsNullOrWhiteSpace(value)) { return null; } return DateOnly.TryParseExact( $"{value.Trim()}-01", "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsed) ? new DateOnly(parsed.Year, parsed.Month, 1) : null; } private static DateOnly? ParseDate(string? value) { if (string.IsNullOrWhiteSpace(value)) { return null; } return DateOnly.TryParseExact( value.Trim(), "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsed) ? parsed : null; } }