using Application.Abstractions.Messaging;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using SharedKernel.Extensions;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
namespace Admin.Pages.Stocks.MarketHoliday;
///
/// KRX 휴장일 관리 — 목록(연도 필터)/추가/삭제. 수집 배치(KrxBackfill/MarketCalendar)의 영업일 판정에 사용되므로
/// 거래일을 휴장일로 잘못 등록하면 해당 날짜 데이터가 영구 결손된다 (추가/삭제 모두 confirm).
///
public class IndexModel(IMediator mediator) : PageModel
{
public int? Year { get; private set; }
public int Total { get; private set; }
public List Years { get; private set; } = [];
public List<(
DateOnly Date,
string DayOfWeek,
string Name
)> Data { get; private set; } = [];
[BindProperty]
public InputModel Input { get; set; } = new();
public sealed class InputModel
{
[Required]
public DateOnly? Date { get; set; }
[Required]
[StringLength(50)]
public string? Name { get; set; }
}
[BindProperty]
public DateOnly DeleteDate { get; set; }
public async Task OnGetAsync(int? year, CancellationToken ct)
{
Year = year;
var result = await mediator.Send(new GetMarketHolidays.Query(year), ct);
Total = result.Total;
Years = [..result.Years];
Data = [..result.List.Select(c => (
c.Date,
CultureInfo.GetCultureInfo("ko-KR").DateTimeFormat.GetDayName(c.Date.DayOfWeek),
c.Name
))];
}
public async Task OnPostAddAsync(int? year, CancellationToken ct)
{
if (!ModelState.IsValid || Input.Date is null || Input.Name is null)
{
TempData["ErrorMessages"] = ModelState.GetErrorMessages();
return RedirectToIndex(year);
}
var result = await mediator.Send(new AddMarketHoliday.Command(Input.Date.Value, Input.Name), ct);
if (result.IsFailure)
{
TempData["ErrorMessages"] = result.Error.Description;
}
else
{
TempData["SuccessMessage"] = $"{Input.Date.Value:yyyy-MM-dd} ({Input.Name}) 휴장일이 등록되었습니다.";
}
return RedirectToIndex(year);
}
public async Task OnPostDeleteAsync(int? year, CancellationToken ct)
{
var result = await mediator.Send(new DeleteMarketHoliday.Command(DeleteDate), ct);
if (result.IsFailure)
{
TempData["ErrorMessages"] = result.Error.Description;
}
else
{
TempData["SuccessMessage"] = $"{DeleteDate:yyyy-MM-dd} 휴장일이 삭제되었습니다.";
}
return RedirectToIndex(year);
}
private RedirectToPageResult RedirectToIndex(int? year)
{
return year.HasValue ? RedirectToPage("/Stocks/MarketHoliday/Index", new { year }) : RedirectToPage("/Stocks/MarketHoliday/Index");
}
}