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

namespace Baya.Test.Api;

public class PatientsApiTests(BayaApiFactory factory) : IClassFixture<BayaApiFactory>
{
    private static object PatientBody(string name, string gender = "female") => new
    {
        displayName = name,
        firstName = "F",
        lastName = "L",
        birthDate = "1950-03-01",
        gender,
        bloodType = "O+",
        initialMedicalNotes = "diabetic"
    };

    [Fact]
    public async Task Create_List_Get_Update_Archive_Lifecycle()
    {
        var client = factory.CreateClient();
        await ProfileTestClient.AuthenticateAsync(factory, client, "09123000001", "customer");

        var create = await client.PostAsJsonAsync("/api/v1/patients/create", PatientBody("Mother"));
        Assert.Equal(HttpStatusCode.OK, create.StatusCode);
        var created = await AuthTestClient.ReadDataAsync(create);
        var id = created.GetProperty("id").GetInt64();
        Assert.Equal("female", created.GetProperty("gender").GetString());
        Assert.Equal("diabetic", created.GetProperty("initialMedicalNotes").GetString());

        var list = await client.GetAsync("/api/v1/patients/list");
        var listData = await AuthTestClient.ReadDataAsync(list);
        Assert.Equal(1, listData.GetProperty("total").GetInt32());

        var get = await client.GetAsync($"/api/v1/patients/get/{id}");
        Assert.Equal(HttpStatusCode.OK, get.StatusCode);

        var update = await client.PostAsJsonAsync($"/api/v1/patients/update/{id}", PatientBody("Mother Renamed", "female"));
        Assert.Equal(HttpStatusCode.OK, update.StatusCode);
        var updated = await AuthTestClient.ReadDataAsync(update);
        Assert.Equal("Mother Renamed", updated.GetProperty("displayName").GetString());

        var archive = await client.PostAsJsonAsync($"/api/v1/patients/archive/{id}", new { });
        Assert.Equal(HttpStatusCode.OK, archive.StatusCode);

        var afterArchive = await client.GetAsync($"/api/v1/patients/get/{id}");
        var archivedData = await AuthTestClient.ReadDataAsync(afterArchive);
        Assert.False(archivedData.GetProperty("isActive").GetBoolean());
    }

    [Fact]
    public async Task Get_And_Update_OfAnotherCustomersPatient_Return404()
    {
        // Customer A creates a patient.
        var clientA = factory.CreateClient();
        await ProfileTestClient.AuthenticateAsync(factory, clientA, "09123000002", "customer");
        var create = await clientA.PostAsJsonAsync("/api/v1/patients/create", PatientBody("A's patient"));
        var aPatientId = (await AuthTestClient.ReadDataAsync(create)).GetProperty("id").GetInt64();

        // Customer B can neither read nor mutate A's patient — existence is not leaked.
        var clientB = factory.CreateClient();
        await ProfileTestClient.AuthenticateAsync(factory, clientB, "09123000003", "customer");

        var get = await clientB.GetAsync($"/api/v1/patients/get/{aPatientId}");
        Assert.Equal(HttpStatusCode.NotFound, get.StatusCode);

        var update = await clientB.PostAsJsonAsync($"/api/v1/patients/update/{aPatientId}", PatientBody("hijack"));
        Assert.Equal(HttpStatusCode.NotFound, update.StatusCode);
    }

    [Fact]
    public async Task List_Unauthenticated_Returns401()
    {
        var client = factory.CreateClient();
        var response = await client.GetAsync("/api/v1/patients/list");
        Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
    }

    [Fact]
    public async Task Create_MissingGender_Returns400()
    {
        var client = factory.CreateClient();
        await ProfileTestClient.AuthenticateAsync(factory, client, "09123000004", "customer");

        var response = await client.PostAsJsonAsync("/api/v1/patients/create", PatientBody("No gender", gender: ""));

        Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
    }
}
