using Microsoft.EntityFrameworkCore;
using OmsorgCore.Application.Abstractions;
using OmsorgCore.Domain.Entities;
using OmsorgCore.Infrastructure.Persistence;

namespace OmsorgCore.Infrastructure.Repositories;

public class EmployeeFacilityDistanceRepository : IEmployeeFacilityDistanceRepository
{
    private readonly OmsorgCoreDbContext _db;

    public EmployeeFacilityDistanceRepository(OmsorgCoreDbContext db)
    {
        _db = db;
    }

    public Task<EmployeeFacilityDistance?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
        => _db.EmployeeFacilityDistances.FirstOrDefaultAsync(d => d.Id == id, cancellationToken);

    public async Task<IReadOnlyList<EmployeeFacilityDistance>> GetByFacilityIdAsync(Guid facilityId, CancellationToken cancellationToken = default)
        => await _db.EmployeeFacilityDistances
            .AsNoTracking()
            .Include(d => d.Employee)
            .Where(d => d.FacilityId == facilityId)
            .OrderBy(d => d.Employee.LastName)
            .ThenBy(d => d.Employee.FirstName)
            .ToListAsync(cancellationToken);

    public Task<EmployeeFacilityDistance?> GetByFacilityAndEmployeeAsync(Guid facilityId, Guid employeeId, CancellationToken cancellationToken = default)
        => _db.EmployeeFacilityDistances.FirstOrDefaultAsync(d => d.FacilityId == facilityId && d.EmployeeId == employeeId, cancellationToken);

    public async Task AddAsync(EmployeeFacilityDistance distance, CancellationToken cancellationToken = default)
        => await _db.EmployeeFacilityDistances.AddAsync(distance, cancellationToken);

    public Task UpdateAsync(EmployeeFacilityDistance distance, CancellationToken cancellationToken = default)
    {
        _db.EmployeeFacilityDistances.Update(distance);
        return Task.CompletedTask;
    }

    public async Task<bool> SoftDeleteAsync(Guid id, CancellationToken cancellationToken = default)
    {
        var distance = await _db.EmployeeFacilityDistances.FirstOrDefaultAsync(d => d.Id == id, cancellationToken);
        if (distance is null)
        {
            return false;
        }

        distance.IsDeleted = true;
        distance.DeletedAt = DateTime.UtcNow;
        return true;
    }

    public async Task<IReadOnlyList<EmployeeFacilityDistance>> GetDeletedAsync(string? search, CancellationToken cancellationToken = default)
    {
        var query = _db.EmployeeFacilityDistances.IgnoreQueryFilters().AsNoTracking().Include(d => d.Employee).Where(d => d.IsDeleted);

        if (!string.IsNullOrWhiteSpace(search))
        {
            var pattern = $"%{search.Trim()}%";
            query = query.Where(d => EF.Functions.ILike(d.Employee.FirstName, pattern) || EF.Functions.ILike(d.Employee.LastName, pattern));
        }

        return await query.OrderByDescending(d => d.DeletedAt).ToListAsync(cancellationToken);
    }

    public async Task<bool> RestoreAsync(Guid id, CancellationToken cancellationToken = default)
    {
        var distance = await _db.EmployeeFacilityDistances.IgnoreQueryFilters().FirstOrDefaultAsync(d => d.Id == id && d.IsDeleted, cancellationToken);
        if (distance is null)
        {
            return false;
        }

        distance.IsDeleted = false;
        distance.DeletedAt = null;
        return true;
    }

    public Task SaveChangesAsync(CancellationToken cancellationToken = default)
        => _db.SaveChangesAsync(cancellationToken);
}
