using System.Net;
using System.Net.Http.Json;
using System.Text.Json;

namespace GerbilManager.Tests;

/// <summary>
/// Gehege-Reinigungszyklus (RennmausPro becken_tb): Enclosure trägt Maße (Size),
/// Kapazität (Capacity), letzte Reinigung (LastCleanedDate) und Reinigungsintervall
/// (CleaningCycleDays). NextCleaningDate = LastCleanedDate + CleaningCycleDays wird
/// berechnet ausgegeben. "mark-cleaned" setzt die letzte Reinigung auf heute.
/// </summary>
public class EnclosureEndpointTests : IClassFixture<ApiFactory>
{
    private readonly ApiFactory _factory;
    public EnclosureEndpointTests(ApiFactory factory) => _factory = factory;

    [Fact]
    public async Task Post_persists_cleaning_fields_and_computes_next_cleaning()
    {
        var client = _factory.CreateClient();

        var resp = await client.PostAsJsonAsync("/enclosures", new
        {
            name = "Reinigungs-Becken",
            notes = "Test",
            size = "120×50 cm",
            capacity = 6,
            lastCleanedDate = "2026-06-01",
            cleaningCycleDays = 14,
        });

        Assert.Equal(HttpStatusCode.Created, resp.StatusCode);
        var dto = JsonDocument.Parse(await resp.Content.ReadAsStringAsync()).RootElement;
        Assert.Equal("120×50 cm", dto.GetProperty("size").GetString());
        Assert.Equal(6, dto.GetProperty("capacity").GetInt32());
        Assert.Equal("2026-06-01", dto.GetProperty("lastCleanedDate").GetString());
        Assert.Equal(14, dto.GetProperty("cleaningCycleDays").GetInt32());
        // 2026-06-01 + 14 Tage = 2026-06-15
        Assert.Equal("2026-06-15", dto.GetProperty("nextCleaningDate").GetString());
    }

    [Fact]
    public async Task NextCleaning_is_null_without_cycle_or_lastCleaned()
    {
        var client = _factory.CreateClient();

        // Nur letzte Reinigung, kein Zyklus -> keine nächste fällige Reinigung.
        var resp = await client.PostAsJsonAsync("/enclosures", new
        {
            name = "Becken ohne Zyklus",
            lastCleanedDate = "2026-06-01",
        });
        var dto = JsonDocument.Parse(await resp.Content.ReadAsStringAsync()).RootElement;
        Assert.Equal(JsonValueKind.Null, dto.GetProperty("nextCleaningDate").ValueKind);
        Assert.Equal(JsonValueKind.Null, dto.GetProperty("cleaningCycleDays").ValueKind);
    }

    [Fact]
    public async Task Put_updates_cleaning_fields()
    {
        var client = _factory.CreateClient();

        var created = JsonDocument.Parse(await (await client.PostAsJsonAsync("/enclosures", new
        {
            name = "Becken-Edit",
            cleaningCycleDays = 7,
        })).Content.ReadAsStringAsync()).RootElement;
        var id = created.GetProperty("id").GetString();

        var put = await client.PutAsJsonAsync($"/enclosures/{id}", new
        {
            name = "Becken-Edit",
            size = "80×40 cm",
            capacity = 4,
            lastCleanedDate = "2026-05-20",
            cleaningCycleDays = 10,
        });
        Assert.Equal(HttpStatusCode.NoContent, put.StatusCode);

        var dto = JsonDocument.Parse(await client.GetStringAsync($"/enclosures/{id}")).RootElement;
        Assert.Equal("80×40 cm", dto.GetProperty("size").GetString());
        Assert.Equal(4, dto.GetProperty("capacity").GetInt32());
        Assert.Equal("2026-05-20", dto.GetProperty("lastCleanedDate").GetString());
        Assert.Equal(10, dto.GetProperty("cleaningCycleDays").GetInt32());
        Assert.Equal("2026-05-30", dto.GetProperty("nextCleaningDate").GetString());
    }

    [Fact]
    public async Task MarkCleaned_sets_lastCleaned_to_today()
    {
        var client = _factory.CreateClient();

        var created = JsonDocument.Parse(await (await client.PostAsJsonAsync("/enclosures", new
        {
            name = "Becken-Mark",
            cleaningCycleDays = 21,
            lastCleanedDate = "2020-01-01",
        })).Content.ReadAsStringAsync()).RootElement;
        var id = created.GetProperty("id").GetString();

        var resp = await client.PostAsync($"/enclosures/{id}/mark-cleaned", null);
        Assert.Equal(HttpStatusCode.OK, resp.StatusCode);

        var dto = JsonDocument.Parse(await resp.Content.ReadAsStringAsync()).RootElement;
        var today = DateOnly.FromDateTime(DateTime.Today);
        Assert.Equal(today.ToString("yyyy-MM-dd"), dto.GetProperty("lastCleanedDate").GetString());
        Assert.Equal(today.AddDays(21).ToString("yyyy-MM-dd"), dto.GetProperty("nextCleaningDate").GetString());
    }

    [Fact]
    public async Task MarkCleaned_unknown_id_returns_404()
    {
        var client = _factory.CreateClient();
        var resp = await client.PostAsync($"/enclosures/{Guid.NewGuid()}/mark-cleaned", null);
        Assert.Equal(HttpStatusCode.NotFound, resp.StatusCode);
    }
}
