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

namespace Baya.Test.Api;

public class NurseBankAccountsApiTests(BayaApiFactory factory) : IClassFixture<BayaApiFactory>
{
    private const string Iban1 = "IR000000000000000000000001";
    private const string Iban2 = "IR000000000000000000000002";
    private const string MismatchIban = "IR000000000000000000000000";

    private static object AccountBody(string iban) => new { bankName = "Bank Melli", accountHolderName = "Nurse Name", iban };

    [Fact]
    public async Task Add_List_Duplicate_And_PrimaryFlip()
    {
        var client = factory.CreateClient();
        await ProfileTestClient.AuthenticateAsync(factory, client, "09124000001", "nurse");
        await client.PostAsJsonAsync("/api/v1/nurse_profiles/upsert",
            new { bio = "b", yearsOfExperience = 5, educationLevel = "", educationField = "", specializationsJson = "[]" });

        // First account: ownership inquiry matches, becomes primary, IBAN masked on the wire.
        var add1 = await client.PostAsJsonAsync("/api/v1/nurse_bank_accounts/add", AccountBody(Iban1));
        Assert.Equal(HttpStatusCode.OK, add1.StatusCode);
        var acc1 = await AuthTestClient.ReadDataAsync(add1);
        var id1 = acc1.GetProperty("id").GetInt64();
        Assert.True(acc1.GetProperty("matchedNationalId").GetBoolean());
        Assert.True(acc1.GetProperty("isPrimary").GetBoolean());
        var masked = acc1.GetProperty("ibanMasked").GetString()!;
        Assert.DoesNotContain(Iban1, masked);
        Assert.EndsWith("0001", masked);

        // Duplicate IBAN is a clean failure via the iban_hash uniqueness — not an unhandled exception.
        var duplicate = await client.PostAsJsonAsync("/api/v1/nurse_bank_accounts/add", AccountBody(Iban1));
        Assert.Equal(HttpStatusCode.BadRequest, duplicate.StatusCode);

        // Second account: not primary.
        var add2 = await client.PostAsJsonAsync("/api/v1/nurse_bank_accounts/add", AccountBody(Iban2));
        var acc2 = await AuthTestClient.ReadDataAsync(add2);
        var id2 = acc2.GetProperty("id").GetInt64();
        Assert.False(acc2.GetProperty("isPrimary").GetBoolean());

        // Flip primary to the second account.
        var setPrimary = await client.PostAsJsonAsync($"/api/v1/nurse_bank_accounts/set_primary/{id2}", new { });
        Assert.Equal(HttpStatusCode.OK, setPrimary.StatusCode);

        var list = await client.GetAsync("/api/v1/nurse_bank_accounts/list");
        var accounts = (await AuthTestClient.ReadDataAsync(list)).EnumerateArray().ToList();
        Assert.Equal(2, accounts.Count);
        Assert.True(Primary(accounts, id2));
        Assert.False(Primary(accounts, id1));
    }

    [Fact]
    public async Task Add_MismatchIban_RecordsMatchedFalse()
    {
        var client = factory.CreateClient();
        await ProfileTestClient.AuthenticateAsync(factory, client, "09124000002", "nurse");
        await client.PostAsJsonAsync("/api/v1/nurse_profiles/upsert",
            new { bio = "b", yearsOfExperience = 5, educationLevel = "", educationField = "", specializationsJson = "[]" });

        var add = await client.PostAsJsonAsync("/api/v1/nurse_bank_accounts/add", AccountBody(MismatchIban));
        Assert.Equal(HttpStatusCode.OK, add.StatusCode);
        var data = await AuthTestClient.ReadDataAsync(add);
        Assert.False(data.GetProperty("matchedNationalId").GetBoolean());
    }

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

    private static bool Primary(IEnumerable<JsonElement> accounts, long id) =>
        accounts.Single(a => a.GetProperty("id").GetInt64() == id).GetProperty("isPrimary").GetBoolean();
}
