using System.Net;
using System.Net.Http.Json;
using Freman.Sample.Web.Contracts;
using Shouldly;
using Freman.Sample.Web.IntegrationTests.TestHost;

namespace Freman.Sample.Web.IntegrationTests.Api;

[Collection(IntegrationTestCollection.Name)]
public class NotesApiTests(IntegrationTestFixture fixture) : IAsyncLifetime
{
    private readonly HttpClient _client = fixture.Factory.CreateClient();

    public async ValueTask InitializeAsync()
    {
        await fixture.ResetDatabaseAsync();
    }

    public ValueTask DisposeAsync() => ValueTask.CompletedTask;

    [Fact]
    public async Task GetNotes_InitiallyEmpty_Returns200AndEmptyList()
    {
        var resp = await _client.GetAsync("/api/notes", TestContext.Current.CancellationToken);
        resp.StatusCode.ShouldBe(HttpStatusCode.OK);

        var notes = await resp.Content.ReadFromJsonAsync<List<NoteDto>>(cancellationToken: TestContext.Current.CancellationToken);
        notes.ShouldNotBeNull();
        notes!.Count.ShouldBe(0);
    }

    [Fact]
    public async Task PostNote_ThenGetNotes_ReturnsTheNewNote()
    {
        var uniqueText = $"test note {Guid.NewGuid():N}";

        var post = await _client.PostAsJsonAsync("/api/notes",
            new CreateNoteRequest { Text = uniqueText },
            cancellationToken: TestContext.Current.CancellationToken);

        post.StatusCode.ShouldBe(HttpStatusCode.Created);

        var notes = await _client.GetFromJsonAsync<List<NoteDto>>("/api/notes", cancellationToken: TestContext.Current.CancellationToken);
        notes.ShouldNotBeNull();
        notes!.Any(n => n.Text == uniqueText).ShouldBeTrue();
    }

    [Fact]
    public async Task DeleteNote_RemovesIt()
    {
        var post = await _client.PostAsJsonAsync("/api/notes", new CreateNoteRequest { Text = "delete me" },
            cancellationToken: TestContext.Current.CancellationToken);
        var created = await post.Content.ReadFromJsonAsync<NoteDto>(cancellationToken: TestContext.Current.CancellationToken);
        created.ShouldNotBeNull();

        var del = await _client.DeleteAsync($"/api/notes/{created!.Id}", TestContext.Current.CancellationToken);
        del.StatusCode.ShouldBe(HttpStatusCode.NoContent);

        var notes = await _client.GetFromJsonAsync<List<NoteDto>>("/api/notes", cancellationToken: TestContext.Current.CancellationToken);
        notes.ShouldNotBeNull();
        notes!.Any(n => n.Id == created.Id).ShouldBeFalse();
    }

    [Fact]
    public async Task DeleteMissingNote_Returns404()
    {
        var del = await _client.DeleteAsync("/api/notes/123456", TestContext.Current.CancellationToken);
        del.StatusCode.ShouldBe(HttpStatusCode.NotFound);
    }
}