using System.Globalization;

namespace SVSim.EmulatedEntrypoint.Services;

/// <summary>
/// JST-anchored period bucketing for ViewerEventCounters. Day/week/month boundaries are
/// 02:00 JST (matching the real-game daily reset). Pure functions, no dependencies.
/// </summary>
public static class JstPeriod
{
    private static readonly TimeSpan Jst = TimeSpan.FromHours(9);
    private const string DayPrefix   = "day:";
    private const string WeekPrefix  = "week:";
    private const string MonthPrefix = "month:";
    public const string AllTime = "all-time";

    /// <summary>
    /// Converts the given instant to a JST-anchored "effective date" by:
    /// 1. Shifting to JST (+09:00)
    /// 2. Subtracting 2 hours so anything before 02:00 JST belongs to the previous day
    /// </summary>
    private static DateTime EffectiveJstDate(DateTimeOffset utcOrAny)
    {
        var jst = utcOrAny.ToOffset(Jst);
        return jst.AddHours(-2).Date;
    }

    public static string DayKey(DateTimeOffset when)
    {
        var d = EffectiveJstDate(when);
        return $"{DayPrefix}{d:yyyy-MM-dd}";
    }

    public static string WeekKey(DateTimeOffset when)
    {
        var d = EffectiveJstDate(when);
        var iso = ISOWeek.GetWeekOfYear(d);
        var year = ISOWeek.GetYear(d);
        return $"{WeekPrefix}{year:D4}-W{iso:D2}";
    }

    public static string MonthKey(DateTimeOffset when)
    {
        var d = EffectiveJstDate(when);
        return $"{MonthPrefix}{d:yyyy-MM}";
    }

    /// <summary>Returns [day, week, month, all-time] keys for the given instant.</summary>
    public static IReadOnlyList<string> AllPeriods(DateTimeOffset when) => new[]
    {
        DayKey(when), WeekKey(when), MonthKey(when), AllTime,
    };
}
