using JobsMedical.Web.Data;
using JobsMedical.Web.Models;
using Microsoft.EntityFrameworkCore;

namespace JobsMedical.Web.Services.Scraping;

/// <summary>
/// Centralizes "what counts as a live listing". Jobs have no end date, so they go stale after a
/// window; shifts expire once their date has passed. Public screens hide anything outside these
/// rules, and <see cref="ListingArchiver"/> flips stale Open rows to Expired so dashboards/DB agree.
/// </summary>
public static class ListingPolicy
{
    /// <summary>A job opening older than this (since posting) is treated as stale and hidden.</summary>
    public const int JobFreshnessDays = 30;

    /// <summary>«آماده به کار» goes stale faster — the person is usually hired within a few weeks.</summary>
    public const int TalentFreshnessDays = 21;

    public static DateTime JobCutoffUtc => DateTime.UtcNow.AddDays(-JobFreshnessDays);
    public static DateTime TalentCutoffUtc => DateTime.UtcNow.AddDays(-TalentFreshnessDays);
}

/// <summary>Sweeps stale listings into the Expired state (archive). Idempotent and cheap.</summary>
public class ListingArchiver
{
    private readonly AppDbContext _db;
    private readonly ILogger<ListingArchiver> _log;

    public ListingArchiver(AppDbContext db, ILogger<ListingArchiver> log)
    {
        _db = db;
        _log = log;
    }

    public async Task<int> ArchiveStaleAsync(CancellationToken ct = default)
    {
        var today = DateOnly.FromDateTime(DateTime.UtcNow);
        var jobCutoff = ListingPolicy.JobCutoffUtc;

        var expiredShifts = await _db.Shifts
            .Where(s => s.Status == ShiftStatus.Open && s.Date < today)
            .ExecuteUpdateAsync(u => u.SetProperty(s => s.Status, ShiftStatus.Expired), ct);

        var expiredJobs = await _db.JobOpenings
            .Where(j => j.Status == ShiftStatus.Open && j.CreatedAt < jobCutoff)
            .ExecuteUpdateAsync(u => u.SetProperty(j => j.Status, ShiftStatus.Expired), ct);

        var talentCutoff = ListingPolicy.TalentCutoffUtc;
        var expiredTalent = await _db.TalentListings
            .Where(t => t.Status == ShiftStatus.Open && t.CreatedAt < talentCutoff)
            .ExecuteUpdateAsync(u => u.SetProperty(t => t.Status, ShiftStatus.Expired), ct);

        if (expiredShifts + expiredJobs + expiredTalent > 0)
            _log.LogInformation("Archived {Shifts} shifts + {Jobs} jobs + {Talent} talent as expired",
                expiredShifts, expiredJobs, expiredTalent);
        return expiredShifts + expiredJobs + expiredTalent;
    }
}
