using OmsorgCore.Application.Abstractions;
using OmsorgCore.Domain.Entities;

namespace OmsorgCore.Application.Services;

public class OrderService : IOrderService
{
    private const string StatusListKey = "OrderStatus";

    private readonly IOrderRepository _orderRepository;
    private readonly IValueListRepository _valueListRepository;

    public OrderService(IOrderRepository orderRepository, IValueListRepository valueListRepository)
    {
        _orderRepository = orderRepository;
        _valueListRepository = valueListRepository;
    }

    public Task<IReadOnlyList<Order>> GetAllAsync(CancellationToken cancellationToken = default)
        => _orderRepository.GetAllAsync(cancellationToken);

    public 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)
        => _orderRepository.GetPagedAsync(search, statusId, facilityId, priority, requiredQualification, shiftType, page, pageSize, cancellationToken);

    public Task<Order?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
        => _orderRepository.GetByIdAsync(id, cancellationToken);

    public async Task<Order> CreateAsync(Order order, CancellationToken cancellationToken = default)
    {
        var initialStatus = await _valueListRepository.GetInitialItemAsync(StatusListKey, cancellationToken)
            ?? throw new InvalidOperationException("Kein initialer Auftragsstatus konfiguriert (DbSeeder.SeedValueListsAsync fehlt).");
        order.StatusId = initialStatus.Id;

        await _orderRepository.AddAsync(order, cancellationToken);
        await _orderRepository.SaveChangesAsync(cancellationToken);
        return order;
    }

    public async Task<UpdateOrderResult> UpdateAsync(Guid id, Order updates, CancellationToken cancellationToken = default)
    {
        var order = await _orderRepository.GetByIdAsync(id, cancellationToken);
        if (order is null)
        {
            return UpdateOrderResult.Fail(UpdateOrderFailureReason.OrderNotFound);
        }

        if (!await _valueListRepository.CanTransitionAsync(order.StatusId, updates.StatusId, cancellationToken))
        {
            return UpdateOrderResult.Fail(UpdateOrderFailureReason.InvalidStatusTransition);
        }

        order.FacilityId = updates.FacilityId;
        order.FacilityContactId = updates.FacilityContactId;
        order.StartDate = updates.StartDate;
        order.EndDate = updates.EndDate;
        order.RequiredQualification = updates.RequiredQualification;
        order.ShiftType = updates.ShiftType;
        order.RequiredHeadcount = updates.RequiredHeadcount;
        order.Conditions = updates.Conditions;
        order.Priority = updates.Priority;
        order.StatusId = updates.StatusId;
        order.UpdatedAt = DateTime.UtcNow;

        await _orderRepository.UpdateAsync(order, cancellationToken);
        await _orderRepository.SaveChangesAsync(cancellationToken);
        return UpdateOrderResult.Ok(order);
    }

    public async Task<bool> DeleteAsync(Guid id, CancellationToken cancellationToken = default)
    {
        var deleted = await _orderRepository.SoftDeleteAsync(id, cancellationToken);
        if (deleted)
        {
            await _orderRepository.SaveChangesAsync(cancellationToken);
        }

        return deleted;
    }

    public Task<IReadOnlyList<Order>> GetDeletedAsync(string? search, CancellationToken cancellationToken = default)
        => _orderRepository.GetDeletedAsync(search, cancellationToken);

    public async Task<bool> RestoreAsync(Guid id, CancellationToken cancellationToken = default)
    {
        var restored = await _orderRepository.RestoreAsync(id, cancellationToken);
        if (restored)
        {
            await _orderRepository.SaveChangesAsync(cancellationToken);
        }

        return restored;
    }
}
