using System.Text.Json;
using JobsMedical.Web.Data;
using JobsMedical.Web.Models;
using JobsMedical.Web.Services.Scraping;
using Microsoft.EntityFrameworkCore;
using WebPush;

namespace JobsMedical.Web.Services;

/// <summary>
/// Sends Web Push notifications (lock-screen) to users' subscribed browsers via VAPID. Rides the
/// same in-app notification records — when users are notified, their subscriptions also get a push.
/// Config (enable + VAPID keys) comes from AppSetting; dead subscriptions (404/410) are pruned.
/// ⚠️ Chrome push goes through FCM (may be filtered in Iran); the Bazaar TWA can use native push.
/// </summary>
public class PushNotifier
{
    private readonly AppDbContext _db;
    private readonly SettingsService _settings;
    private readonly ILogger<PushNotifier> _log;

    public PushNotifier(AppDbContext db, SettingsService settings, ILogger<PushNotifier> log)
    {
        _db = db;
        _settings = settings;
        _log = log;
    }

    public async Task PushToUsersAsync(IReadOnlyCollection<int> userIds, string title, string? body, string url)
    {
        if (userIds.Count == 0) return;
        var s = await _settings.GetAsync();
        if (!s.PushEnabled || string.IsNullOrWhiteSpace(s.VapidPublicKey) || string.IsNullOrWhiteSpace(s.VapidPrivateKey))
            return;

        var subs = await (from sub in _db.WebPushSubscriptions
                          join v in _db.Visitors on sub.VisitorId equals v.Id
                          where v.UserId != null && userIds.Contains(v.UserId.Value)
                          select sub).ToListAsync();
        if (subs.Count == 0) return;

        var client = new WebPushClient();
        var vapid = new VapidDetails(s.VapidSubject ?? "mailto:admin@hamkadr.ir", s.VapidPublicKey, s.VapidPrivateKey);
        var payload = JsonSerializer.Serialize(new { title, body, url });

        var dead = new List<WebPushSubscription>();
        foreach (var sub in subs)
        {
            try
            {
                await client.SendNotificationAsync(
                    new WebPush.PushSubscription(sub.Endpoint, sub.P256dh, sub.Auth), payload, vapid);
            }
            catch (WebPushException ex) when ((int)ex.StatusCode is 404 or 410)
            {
                dead.Add(sub);   // subscription expired/gone
            }
            catch (Exception ex)
            {
                _log.LogWarning(ex, "Web push send failed for one subscription");
            }
        }
        if (dead.Count > 0)
        {
            _db.WebPushSubscriptions.RemoveRange(dead);
            await _db.SaveChangesAsync();
        }
    }
}
