namespace JSMR.Infrastructure.Common.Time;

public abstract class TimeProvider : ITimeProvider
{
    protected abstract string Id { get; }
    protected abstract string[] TimeZoneIds { get; }

    private readonly IClock _clock;
    private readonly TimeZoneInfo _timeZone;

    public TimeProvider(IClock clock)
    {
        _clock = clock;
        _timeZone = ResolveTimeZone();
    }

    private TimeZoneInfo ResolveTimeZone()
    {
        foreach (string timeZoneId in TimeZoneIds)
        {
            if (TimeZoneInfo.TryFindSystemTimeZoneById(timeZoneId, out TimeZoneInfo? timeZoneInfo))
                return timeZoneInfo;
        }

        throw new TimeZoneNotFoundException($"Unable to resolve time zone for: {Id} ({string.Join(" / ", TimeZoneIds)})");
    }

    public DateTimeOffset Now() => TimeZoneInfo.ConvertTime(_clock.UtcNow, _timeZone);
    public DateTimeOffset Local(DateTimeOffset offset) => TimeZoneInfo.ConvertTime(offset, _timeZone);

    public DateTimeOffset Local(int year, int month, int day, int hour)
    {
        DateTime local = new(year, month, day, hour, 0, 0, DateTimeKind.Unspecified);
        TimeSpan offset = _timeZone.GetUtcOffset(local);

        return new DateTimeOffset(local, offset);
    }
}