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;

[Authorize(Roles = "Admin")]
public class ReviewModel : PageModel
{
    private readonly AppDbContext _db;
    private readonly IListingParser _parser;

    public ReviewModel(AppDbContext db, IListingParser parser)
    {
        _db = db;
        _parser = parser;
    }

    public RawListing? Raw { get; private set; }
    public ParsedListing? Parsed { get; private set; }
    public List<Facility> Facilities { get; private set; } = new();
    public List<Role> Roles { get; private set; } = new();

    // The editable form (prefilled from the parser, admin can override everything).
    [BindProperty] public ListingKind Kind { get; set; }
    [BindProperty] public int FacilityId { get; set; }
    [BindProperty] public int RoleId { get; set; }
    [BindProperty] public string? Description { get; set; }
    // Shift fields
    [BindProperty] public DateOnly ShiftDate { get; set; }
    [BindProperty] public ShiftType ShiftType { get; set; }
    [BindProperty] public TimeOnly StartTime { get; set; }
    [BindProperty] public TimeOnly EndTime { get; set; }
    [BindProperty] public long? PayAmount { get; set; }
    [BindProperty] public int? SharePercent { get; set; }
    [BindProperty] public bool Negotiable { get; set; }
    [BindProperty] public Gender GenderRequirement { get; set; }
    // Job fields
    [BindProperty] public string? Title { get; set; }
    [BindProperty] public EmploymentType EmploymentType { get; set; }
    [BindProperty] public long? SalaryMin { get; set; }
    [BindProperty] public long? SalaryMax { get; set; }

    public async Task<IActionResult> OnGetAsync(int id)
    {
        await LoadListsAsync();
        Raw = await _db.RawListings.FirstOrDefaultAsync(r => r.Id == id);
        if (Raw is null) return NotFound();

        Parsed = _parser.Parse(Raw.RawText,
            Roles.Select(r => r.Name), await CityNamesAsync(), await DistrictNamesAsync());

        // Prefill the form from the parser's best guess.
        Kind = Parsed.Kind;
        RoleId = Roles.FirstOrDefault(r => r.Name == Parsed.RoleName)?.Id ?? Roles.FirstOrDefault()?.Id ?? 0;
        ShiftType = Parsed.ShiftType ?? ShiftType.Day;
        EmploymentType = Parsed.EmploymentType ?? EmploymentType.FullTime;
        (StartTime, EndTime) = DefaultTimes(ShiftType);
        ShiftDate = DateOnly.FromDateTime(DateTime.UtcNow).AddDays(1);
        Negotiable = Parsed.PayNegotiable;
        SharePercent = Parsed.SharePercent;
        GenderRequirement = Parsed.Gender;
        if (Parsed.PayAmount is not null) { PayAmount = Parsed.PayAmount; SalaryMin = Parsed.PayAmount; }
        Description = Raw.RawText;
        Title = Parsed.RoleName is not null ? $"استخدام {Parsed.RoleName}" : "موقعیت استخدامی";
        return Page();
    }

    public async Task<IActionResult> OnPostPublishAsync(int id)
    {
        Raw = await _db.RawListings.FirstOrDefaultAsync(r => r.Id == id);
        if (Raw is null) return NotFound();

        if (Kind == ListingKind.Shift)
        {
            var role = await _db.Roles.FindAsync(RoleId);
            var shift = new Shift
            {
                FacilityId = FacilityId,
                RoleId = RoleId,
                Date = ShiftDate,
                StartTime = StartTime,
                EndTime = EndTime,
                ShiftType = ShiftType,
                SpecialtyRequired = role?.Name ?? "",
                Description = Description,
                PayType = Negotiable ? PayType.Negotiable
                    : (PayAmount is null && SharePercent is not null ? PayType.Percentage : PayType.PerShift),
                PayAmount = Negotiable ? null : PayAmount,
                SharePercent = Negotiable ? null : SharePercent,
                GenderRequirement = GenderRequirement,
                Status = ShiftStatus.Open,
                Source = ShiftSource.Aggregated,
                SourceUrl = Raw.SourceUrl,
            };
            _db.Shifts.Add(shift);
            await _db.SaveChangesAsync();
            Raw.Status = RawListingStatus.Normalized;
            Raw.LinkedShiftId = shift.Id;
        }
        else
        {
            var job = new JobOpening
            {
                FacilityId = FacilityId,
                RoleId = RoleId,
                Title = string.IsNullOrWhiteSpace(Title) ? "موقعیت استخدامی" : Title.Trim(),
                EmploymentType = EmploymentType,
                SalaryMin = Negotiable ? null : SalaryMin,
                SalaryMax = Negotiable ? null : SalaryMax,
                GenderRequirement = GenderRequirement,
                Description = Description,
                Status = ShiftStatus.Open,
                Source = ShiftSource.Aggregated,
                SourceUrl = Raw.SourceUrl,
            };
            _db.JobOpenings.Add(job);
            Raw.Status = RawListingStatus.Normalized;
        }
        await _db.SaveChangesAsync();
        return RedirectToPage("/Admin/Index");
    }

    public async Task<IActionResult> OnPostDiscardAsync(int id)
    {
        var raw = await _db.RawListings.FirstOrDefaultAsync(r => r.Id == id);
        if (raw is null) return NotFound();
        raw.Status = RawListingStatus.Discarded;
        await _db.SaveChangesAsync();
        return RedirectToPage("/Admin/Index");
    }

    private static (TimeOnly, TimeOnly) DefaultTimes(ShiftType t) => t switch
    {
        ShiftType.Day => (new TimeOnly(8, 0), new TimeOnly(14, 0)),
        ShiftType.Evening => (new TimeOnly(14, 0), new TimeOnly(20, 0)),
        ShiftType.Night => (new TimeOnly(20, 0), new TimeOnly(8, 0)),
        _ => (new TimeOnly(8, 0), new TimeOnly(8, 0)),
    };

    private async Task LoadListsAsync()
    {
        Facilities = await _db.Facilities.Include(f => f.City).OrderBy(f => f.Name).ToListAsync();
        Roles = await _db.Roles.Where(r => r.IsActive).OrderBy(r => r.SortOrder).ToListAsync();
    }

    private Task<List<string>> CityNamesAsync() => _db.Cities.Select(c => c.Name).ToListAsync();
    private Task<List<string>> DistrictNamesAsync() => _db.Districts.Select(d => d.Name).ToListAsync();
}
