using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using ROLAC.API.Data;

namespace ROLAC.API.Services.Notifications;

/// <summary>
/// Supplies the current SMTP/Line settings from the <c>NotificationSetting</c> singleton row,
/// caching a snapshot in memory so send paths don't hit the DB on every message. Registered as a
/// singleton; the Settings UI calls <see cref="Reload"/> after an edit so changes take effect
/// without restarting the API. Falls back to the "Smtp"/"Line" appsettings sections if the row
/// has not been seeded yet.
/// </summary>
public interface INotificationSettingsService
{
    SmtpOptions GetSmtp();
    LineOptions GetLine();
    WebPushOptions GetWebPush();
    void Reload();
}

public sealed class NotificationSettingsService : INotificationSettingsService
{
    private readonly IServiceScopeFactory _scopeFactory;
    private readonly IOptions<SmtpOptions> _smtpFallback;
    private readonly IOptions<LineOptions> _lineFallback;
    private readonly object _gate = new();

    private SmtpOptions? _smtp;
    private LineOptions? _line;
    private WebPushOptions? _webPush;

    public NotificationSettingsService(
        IServiceScopeFactory scopeFactory,
        IOptions<SmtpOptions> smtpFallback,
        IOptions<LineOptions> lineFallback)
    {
        _scopeFactory = scopeFactory;
        _smtpFallback = smtpFallback;
        _lineFallback = lineFallback;
    }

    public SmtpOptions GetSmtp()
    {
        EnsureLoaded();
        return _smtp!;
    }

    public LineOptions GetLine()
    {
        EnsureLoaded();
        return _line!;
    }

    public WebPushOptions GetWebPush()
    {
        EnsureLoaded();
        return _webPush!;
    }

    public void Reload()
    {
        lock (_gate)
        {
            _smtp = null;
            _line = null;
            _webPush = null;
        }
    }

    private void EnsureLoaded()
    {
        lock (_gate)
        {
            if (_smtp is not null && _line is not null && _webPush is not null)
                return;

            using var scope = _scopeFactory.CreateScope();
            var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
            var row = db.NotificationSettings.AsNoTracking().OrderBy(s => s.Id).FirstOrDefault();

            if (row is null)
            {
                // Not seeded yet — use the appsettings values so sends still work. Web push has no
                // appsettings fallback; it stays disabled until the row exists with VAPID keys.
                _smtp = _smtpFallback.Value;
                _line = _lineFallback.Value;
                _webPush = new WebPushOptions();
                return;
            }

            _smtp = new SmtpOptions
            {
                Host        = row.SmtpHost,
                Port        = row.SmtpPort,
                UseSsl      = row.SmtpUseSsl,
                User        = row.SmtpUser,
                Password    = row.SmtpPassword,
                FromAddress = row.FromAddress,
                FromName    = row.FromName,
            };
            _line = new LineOptions
            {
                ChannelAccessToken = row.LineChannelAccessToken,
                ChannelSecret      = row.LineChannelSecret,
            };
            _webPush = new WebPushOptions
            {
                PublicKey  = row.VapidPublicKey,
                PrivateKey = row.VapidPrivateKey,
                Subject    = row.VapidSubject,
            };
        }
    }
}
