using System.Security.Claims;
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.Me;

/// <summary>The employee / job-seeker (کارجو) panel — the staff-side counterpart to /Employer.</summary>
[Authorize]
public class IndexModel : PageModel
{
    private readonly AppDbContext _db;
    private readonly RecommendationService _recs;
    private readonly InterestService _interest;

    public IndexModel(AppDbContext db, RecommendationService recs, InterestService interest)
    {
        _db = db;
        _recs = recs;
        _interest = interest;
    }

    public User? CurrentUser { get; private set; }
    public UserPreferences? Prefs { get; private set; }
    public List<Recommendation> Recommendations { get; private set; } = new();
    public List<Shift> SavedShifts { get; private set; } = new();
    public List<Shift> AppliedShifts { get; private set; } = new();
    public List<JobOpening> AppliedJobs { get; private set; } = new();
    public Dictionary<int, ApplicationStatus> ShiftAppStatus { get; private set; } = new();
    public Dictionary<int, ApplicationStatus> JobAppStatus { get; private set; } = new();
    public bool ProfileIncomplete { get; private set; }

    public async Task OnGetAsync()
    {
        var userId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
        CurrentUser = await _db.Users.FindAsync(userId);
        ProfileIncomplete = CurrentUser is not null &&
            (string.IsNullOrWhiteSpace(CurrentUser.FullName) || CurrentUser.Avatar is null || CurrentUser.Resume is null);
        Prefs = await _interest.GetPreferencesAsync();
        Recommendations = await _recs.GetForVisitorAsync(6);

        var visitorIds = await _db.Visitors.Where(v => v.UserId == userId).Select(v => v.Id).ToListAsync();
        var events = await _db.InterestEvents.Where(e => visitorIds.Contains(e.VisitorId)).ToListAsync();

        var savedShiftIds = events.Where(e => e.EventType == InterestEventType.Save && e.ShiftId != null)
            .Select(e => e.ShiftId!.Value).Distinct().ToList();
        var appliedShiftIds = events.Where(e => e.EventType == InterestEventType.Apply && e.ShiftId != null)
            .Select(e => e.ShiftId!.Value).Distinct().ToList();
        var appliedJobIds = events.Where(e => e.EventType == InterestEventType.Apply && e.JobOpeningId != null)
            .Select(e => e.JobOpeningId!.Value).Distinct().ToList();

        SavedShifts = await ShiftsByIds(savedShiftIds);
        AppliedShifts = await ShiftsByIds(appliedShiftIds);
        AppliedJobs = await _db.JobOpenings
            .Include(j => j.Facility).ThenInclude(f => f.City).Include(j => j.Role)
            .Where(j => appliedJobIds.Contains(j.Id)).ToListAsync();

        // Latest application status per applied listing (employer accept/reject shows here).
        ShiftAppStatus = events.Where(e => e.EventType == InterestEventType.Apply && e.ShiftId != null)
            .GroupBy(e => e.ShiftId!.Value)
            .ToDictionary(g => g.Key, g => g.OrderByDescending(e => e.CreatedAt).First().Status);
        JobAppStatus = events.Where(e => e.EventType == InterestEventType.Apply && e.JobOpeningId != null)
            .GroupBy(e => e.JobOpeningId!.Value)
            .ToDictionary(g => g.Key, g => g.OrderByDescending(e => e.CreatedAt).First().Status);
    }

    public Task<IActionResult> OnPostWithdrawShiftAsync(int id) => WithdrawAsync(id, isJob: false);
    public Task<IActionResult> OnPostWithdrawJobAsync(int id) => WithdrawAsync(id, isJob: true);

    private async Task<IActionResult> WithdrawAsync(int id, bool isJob)
    {
        var userId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
        var visitorIds = await _db.Visitors.Where(v => v.UserId == userId).Select(v => v.Id).ToListAsync();
        var evs = _db.InterestEvents.Where(e => visitorIds.Contains(e.VisitorId)
            && e.EventType == InterestEventType.Apply
            && (isJob ? e.JobOpeningId == id : e.ShiftId == id));
        _db.InterestEvents.RemoveRange(evs);
        await _db.SaveChangesAsync();
        return RedirectToPage();
    }

    private Task<List<Shift>> ShiftsByIds(List<int> ids) => _db.Shifts
        .Include(s => s.Facility).ThenInclude(f => f.City)
        .Include(s => s.Facility).ThenInclude(f => f.District)
        .Include(s => s.Role)
        .Where(s => ids.Contains(s.Id)).ToListAsync();
}
