using OmsorgCore.Application.Services;
using OmsorgCore.Domain.Entities;
using OmsorgCore.Tests.TestDoubles;

namespace OmsorgCore.Tests.Services;

public class FacilityQualificationRateServiceTests
{
    [Fact]
    public async Task CreateAsync_PersistsAllFields()
    {
        var repository = new FakeFacilityQualificationRateRepository();
        var sut = new FacilityQualificationRateService(repository);
        var facilityId = Guid.NewGuid();

        var rate = new FacilityQualificationRate
        {
            FacilityId = facilityId,
            Qualification = "Altenpfleger/in",
            Rate = 38.50m
        };

        var created = await sut.CreateAsync(rate);

        Assert.Equal("Altenpfleger/in", created.Qualification);
        Assert.Equal(38.50m, created.Rate);
        Assert.Equal(facilityId, created.FacilityId);
    }

    [Fact]
    public async Task GetByFacilityIdAsync_ReturnsOnlyRatesOfThatFacility()
    {
        var repository = new FakeFacilityQualificationRateRepository();
        var sut = new FacilityQualificationRateService(repository);
        var facilityIdA = Guid.NewGuid();
        var facilityIdB = Guid.NewGuid();

        await sut.CreateAsync(new FacilityQualificationRate { FacilityId = facilityIdA, Qualification = "Pflegehelfer/in", Rate = 25 });
        await sut.CreateAsync(new FacilityQualificationRate { FacilityId = facilityIdA, Qualification = "Altenpfleger/in", Rate = 38.50m });
        await sut.CreateAsync(new FacilityQualificationRate { FacilityId = facilityIdB, Qualification = "Pflegehelfer/in", Rate = 24 });

        var ratesForA = await sut.GetByFacilityIdAsync(facilityIdA);

        Assert.Equal(2, ratesForA.Count);
        Assert.All(ratesForA, r => Assert.Equal(facilityIdA, r.FacilityId));
    }

    [Fact]
    public async Task UpdateAsync_UpdatesAllMutableFields_AndReturnsUpdatedRate()
    {
        var repository = new FakeFacilityQualificationRateRepository();
        var sut = new FacilityQualificationRateService(repository);
        var created = await sut.CreateAsync(new FacilityQualificationRate { FacilityId = Guid.NewGuid(), Qualification = "Pflegehelfer/in", Rate = 25 });

        var updates = new FacilityQualificationRate
        {
            Qualification = "Altenpfleger/in",
            Rate = 38.50m
        };

        var updated = await sut.UpdateAsync(created.Id, updates);

        Assert.NotNull(updated);
        Assert.Equal("Altenpfleger/in", updated!.Qualification);
        Assert.Equal(38.50m, updated.Rate);
        Assert.NotNull(updated.UpdatedAt);
    }

    [Fact]
    public async Task UpdateAsync_UnknownId_ReturnsNull()
    {
        var repository = new FakeFacilityQualificationRateRepository();
        var sut = new FacilityQualificationRateService(repository);

        var updated = await sut.UpdateAsync(Guid.NewGuid(), new FacilityQualificationRate { Qualification = "X", Rate = 1 });

        Assert.Null(updated);
    }

    [Fact]
    public async Task DeleteAsync_ThenGetDeletedAsync_ReturnsSoftDeletedRate()
    {
        var repository = new FakeFacilityQualificationRateRepository();
        var sut = new FacilityQualificationRateService(repository);
        var created = await sut.CreateAsync(new FacilityQualificationRate { FacilityId = Guid.NewGuid(), Qualification = "Pflegehelfer/in", Rate = 25 });

        var deleted = await sut.DeleteAsync(created.Id);
        var deletedList = await sut.GetDeletedAsync(null);

        Assert.True(deleted);
        Assert.Contains(deletedList, r => r.Id == created.Id);
    }

    [Fact]
    public async Task RestoreAsync_UndoesSoftDelete()
    {
        var repository = new FakeFacilityQualificationRateRepository();
        var sut = new FacilityQualificationRateService(repository);
        var created = await sut.CreateAsync(new FacilityQualificationRate { FacilityId = Guid.NewGuid(), Qualification = "Pflegehelfer/in", Rate = 25 });
        await sut.DeleteAsync(created.Id);

        var restored = await sut.RestoreAsync(created.Id);
        var deletedList = await sut.GetDeletedAsync(null);

        Assert.True(restored);
        Assert.DoesNotContain(deletedList, r => r.Id == created.Id);
    }
}
