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

namespace OmsorgCore.Tests.Services;

public class FacilityServiceTests
{
    [Fact]
    public async Task CreateAsync_PersistsAllStammdatenFields()
    {
        var repository = new FakeFacilityRepository();
        var sut = new FacilityService(repository);

        var facility = new Facility
        {
            Name = "Pflegeheim Musterstadt",
            FacilityType = "Pflegeheim",
            Street = "Musterstraße 1",
            PostalCode = "12345",
            City = "Musterstadt",
            Country = "Deutschland",
            BillingStreet = "Zentrale Buchhaltung 9",
            BillingPostalCode = "54321",
            BillingCity = "Neustadt",
            BillingCountry = "Deutschland"
        };

        var created = await sut.CreateAsync(facility);
        var stored = await sut.GetByIdAsync(created.Id);

        Assert.NotNull(stored);
        Assert.Equal("Pflegeheim Musterstadt", stored!.Name);
        Assert.Equal("Pflegeheim", stored.FacilityType);
        Assert.Equal("Musterstraße 1", stored.Street);
        Assert.Equal("12345", stored.PostalCode);
        Assert.Equal("Musterstadt", stored.City);
        Assert.Equal("Zentrale Buchhaltung 9", stored.BillingStreet);
        Assert.Equal("54321", stored.BillingPostalCode);
        Assert.Equal("Neustadt", stored.BillingCity);
        Assert.Equal("Lead", stored.CrmStatus);
    }

    [Fact]
    public async Task GetAllAsync_ReturnsCreatedFacilities()
    {
        var repository = new FakeFacilityRepository();
        var sut = new FacilityService(repository);

        await sut.CreateAsync(new Facility { Name = "Sozialstation Nord" });

        var all = await sut.GetAllAsync();

        Assert.Single(all);
    }

    [Fact]
    public async Task UpdateAsync_UpdatesAllMutableFields_AndReturnsUpdatedFacility()
    {
        var repository = new FakeFacilityRepository();
        var sut = new FacilityService(repository);
        var created = await sut.CreateAsync(new Facility { Name = "Pflegeheim Musterstadt" });

        var updates = new Facility
        {
            Name = "Pflegeheim Musterstadt GmbH",
            CrmStatus = "Kunde",
            FacilityType = "Pflegeheim",
            Street = "Neue Straße 2",
            PostalCode = "54321",
            City = "Neustadt",
            BillingStreet = "Rechnungsstraße 3",
            BillingPostalCode = "54321",
            BillingCity = "Neustadt"
        };

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

        Assert.NotNull(updated);
        Assert.Equal("Pflegeheim Musterstadt GmbH", updated!.Name);
        Assert.Equal("Kunde", updated.CrmStatus);
        Assert.Equal("Neue Straße 2", updated.Street);
        Assert.Equal("Rechnungsstraße 3", updated.BillingStreet);
        Assert.NotNull(updated.UpdatedAt);
    }

    [Fact]
    public async Task UpdateAsync_PersistsKonditionenFields()
    {
        var repository = new FakeFacilityRepository();
        var sut = new FacilityService(repository);
        var created = await sut.CreateAsync(new Facility { Name = "Pflegeheim Musterstadt" });

        var updates = new Facility
        {
            Name = "Pflegeheim Musterstadt",
            CrmStatus = "Kunde",
            BillingRate = 32.5m,
            NightSurchargePercent = 25,
            SaturdaySurchargePercent = 15,
            SundaySurchargePercent = 20,
            HolidaySurchargePercent = 50,
            TravelCostMode = "ProKilometer",
            TravelCostRate = 10,
            TravelCostPerKm = 0.42m,
            MealAllowanceRate = 14,
            MinimumHours = 4,
            BillingInterval = "Monatlich",
            PaymentTermDays = 14,
            IndividualAgreements = "Sonderkonditionen Wochenende"
        };

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

        Assert.NotNull(updated);
        Assert.Equal(32.5m, updated!.BillingRate);
        Assert.Equal(25, updated.NightSurchargePercent);
        Assert.Equal(15, updated.SaturdaySurchargePercent);
        Assert.Equal(20, updated.SundaySurchargePercent);
        Assert.Equal(50, updated.HolidaySurchargePercent);
        Assert.Equal("ProKilometer", updated.TravelCostMode);
        Assert.Equal(10, updated.TravelCostRate);
        Assert.Equal(0.42m, updated.TravelCostPerKm);
        Assert.Equal(14, updated.MealAllowanceRate);
        Assert.Equal(4, updated.MinimumHours);
        Assert.Equal("Monatlich", updated.BillingInterval);
        Assert.Equal(14, updated.PaymentTermDays);
        Assert.Equal("Sonderkonditionen Wochenende", updated.IndividualAgreements);
    }

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

        var updated = await sut.UpdateAsync(Guid.NewGuid(), new Facility { Name = "X" });

        Assert.Null(updated);
    }

    [Fact]
    public async Task GetPagedAsync_FiltersBySearchAndCrmStatus_AndPaginates()
    {
        var repository = new FakeFacilityRepository();
        var sut = new FacilityService(repository);

        await sut.CreateAsync(new Facility { Name = "Anna-Haus", CrmStatus = "Kunde" });
        await sut.CreateAsync(new Facility { Name = "Bernd-Zentrum", CrmStatus = "Lead" });
        await sut.CreateAsync(new Facility { Name = "Anna-Zentrum", CrmStatus = "Lead" });

        var (items, totalCount) = await sut.GetPagedAsync(search: "anna", crmStatus: "Kunde", followUpDueOnly: false, page: 1, pageSize: 10);

        Assert.Equal(1, totalCount);
        Assert.Single(items);
        Assert.Equal("Anna-Haus", items[0].Name);
    }

    [Fact]
    public async Task GetPagedAsync_PaginatesResults()
    {
        var repository = new FakeFacilityRepository();
        var sut = new FacilityService(repository);

        await sut.CreateAsync(new Facility { Name = "Eins" });
        await sut.CreateAsync(new Facility { Name = "Zwei" });
        await sut.CreateAsync(new Facility { Name = "Drei" });

        var (items, totalCount) = await sut.GetPagedAsync(search: null, crmStatus: null, followUpDueOnly: false, page: 2, pageSize: 2);

        Assert.Equal(3, totalCount);
        Assert.Single(items);
    }
}
