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

namespace OmsorgCore.Infrastructure.Repositories;

public class OrderRepository : IOrderRepository
{
    private readonly OmsorgCoreDbContext _db;

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

    public Task<Order?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
        => _db.Orders.Include(o => o.Status).FirstOrDefaultAsync(o => o.Id == id, cancellationToken);

    public async Task<IReadOnlyList<Order>> GetAllAsync(CancellationToken cancellationToken = default)
        => await _db.Orders.AsNoTracking().Include(o => o.Status).ToListAsync(cancellationToken);

    public async Task<(IReadOnlyList<Order> Items, int TotalCount)> GetPagedAsync(
        string? search,
        Guid? statusId,
        Guid? facilityId,
        string? priority,
        string? requiredQualification,
        string? shiftType,
        int page,
        int pageSize,
        CancellationToken cancellationToken = default)
    {
        var query = _db.Orders.AsNoTracking().Include(o => o.Status).Where(o => !o.IsDeleted);

        if (!string.IsNullOrWhiteSpace(search))
        {
            var pattern = $"%{search.Trim()}%";
            query = query.Where(o => o.RequiredQualification != null && EF.Functions.ILike(o.RequiredQualification, pattern));
        }

        if (statusId.HasValue)
        {
            query = query.Where(o => o.StatusId == statusId.Value);
        }

        if (facilityId.HasValue)
        {
            query = query.Where(o => o.FacilityId == facilityId.Value);
        }

        if (!string.IsNullOrWhiteSpace(priority))
        {
            query = query.Where(o => o.Priority == priority);
        }

        if (!string.IsNullOrWhiteSpace(requiredQualification))
        {
            query = query.Where(o => o.RequiredQualification == requiredQualification);
        }

        if (!string.IsNullOrWhiteSpace(shiftType))
        {
            query = query.Where(o => o.ShiftType == shiftType);
        }

        var totalCount = await query.CountAsync(cancellationToken);

        var items = await query
            .OrderBy(o => o.StartDate)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync(cancellationToken);

        return (items, totalCount);
    }

    public async Task AddAsync(Order order, CancellationToken cancellationToken = default)
        => await _db.Orders.AddAsync(order, cancellationToken);

    public Task UpdateAsync(Order order, CancellationToken cancellationToken = default)
    {
        _db.Orders.Update(order);
        return Task.CompletedTask;
    }

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

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

    public async Task<IReadOnlyList<Order>> GetDeletedAsync(string? search, CancellationToken cancellationToken = default)
    {
        var query = _db.Orders.IgnoreQueryFilters().AsNoTracking().Include(o => o.Status).Where(o => o.IsDeleted);

        if (!string.IsNullOrWhiteSpace(search))
        {
            var pattern = $"%{search.Trim()}%";
            query = query.Where(o => o.RequiredQualification != null && EF.Functions.ILike(o.RequiredQualification, pattern));
        }

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

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

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

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