using JobsMedical.Web.Data;
using JobsMedical.Web.Models;
using JobsMedical.Web.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;

namespace JobsMedical.Web.Pages.Admin;

/// <summary>Role taxonomy hygiene — dynamic ingestion can mint near-duplicate roles over time
/// («کمک‌یار» vs «کمک بهیار»). This screen lists every role with its usage and lets an admin merge
/// one role into another (reassigning all its listings/preferences) or toggle a role's visibility.</summary>
[Authorize(Roles = "Admin")]
public class RolesModel : PageModel
{
    private readonly AppDbContext _db;
    public RolesModel(AppDbContext db) => _db = db;

    public record RoleStat(Role Role, int Shifts, int Jobs, int Talent)
    {
        public int Total => Shifts + Jobs + Talent;
    }

    public List<RoleStat> Stats { get; private set; } = new();
    [TempData] public string? Message { get; set; }

    public async Task OnGetAsync() => await LoadAsync();

    private async Task LoadAsync()
    {
        var roles = await _db.Roles.OrderBy(r => r.Category).ThenBy(r => r.Name).ToListAsync();
        var sc = await _db.Shifts.GroupBy(s => s.RoleId).Select(g => new { g.Key, C = g.Count() }).ToDictionaryAsync(x => x.Key, x => x.C);
        var jc = await _db.JobOpenings.GroupBy(j => j.RoleId).Select(g => new { g.Key, C = g.Count() }).ToDictionaryAsync(x => x.Key, x => x.C);
        var tc = await _db.TalentListings.GroupBy(t => t.RoleId).Select(g => new { g.Key, C = g.Count() }).ToDictionaryAsync(x => x.Key, x => x.C);
        Stats = roles.Select(r => new RoleStat(r, sc.GetValueOrDefault(r.Id), jc.GetValueOrDefault(r.Id), tc.GetValueOrDefault(r.Id)))
            .OrderByDescending(x => x.Total).ToList();
    }

    /// <summary>Move every reference from <paramref name="sourceId"/> to <paramref name="targetId"/>
    /// (listings — the Restrict FKs that would otherwise block — plus preferences/alerts/profiles),
    /// then delete the now-empty source role.</summary>
    public async Task<IActionResult> OnPostMergeAsync(int sourceId, int targetId)
    {
        if (sourceId == 0 || targetId == 0 || sourceId == targetId)
        { Message = "نقش مبدأ و مقصد را درست انتخاب کن."; return RedirectToPage(); }

        var source = await _db.Roles.FindAsync(sourceId);
        var target = await _db.Roles.FindAsync(targetId);
        if (source is null || target is null) { Message = "نقش پیدا نشد."; return RedirectToPage(); }

        var s = await _db.Shifts.Where(x => x.RoleId == sourceId).ExecuteUpdateAsync(u => u.SetProperty(x => x.RoleId, targetId));
        var j = await _db.JobOpenings.Where(x => x.RoleId == sourceId).ExecuteUpdateAsync(u => u.SetProperty(x => x.RoleId, targetId));
        var t = await _db.TalentListings.Where(x => x.RoleId == sourceId).ExecuteUpdateAsync(u => u.SetProperty(x => x.RoleId, targetId));
        // Nullable references too, so a saved preference/alert follows the merge instead of dangling.
        await _db.UserPreferences.Where(x => x.RoleId == sourceId).ExecuteUpdateAsync(u => u.SetProperty(x => x.RoleId, (int?)targetId));
        await _db.JobAlerts.Where(x => x.RoleId == sourceId).ExecuteUpdateAsync(u => u.SetProperty(x => x.RoleId, (int?)targetId));
        await _db.DoctorProfiles.Where(x => x.RoleId == sourceId).ExecuteUpdateAsync(u => u.SetProperty(x => x.RoleId, (int?)targetId));

        _db.Roles.Remove(source);
        await _db.SaveChangesAsync();

        string P(int n) => JalaliDate.ToPersianDigits(n.ToString());
        Message = $"«{source.Name}» در «{target.Name}» ادغام شد — منتقل‌شده: {P(s)} شیفت، {P(j)} استخدام، {P(t)} آماده‌به‌کار.";
        return RedirectToPage();
    }

    /// <summary>Hide a role from filters/forms without deleting it (keeps its listings intact).</summary>
    public async Task<IActionResult> OnPostToggleAsync(int id)
    {
        var role = await _db.Roles.FindAsync(id);
        if (role is not null) { role.IsActive = !role.IsActive; await _db.SaveChangesAsync(); }
        return RedirectToPage();
    }
}
