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

namespace Baya.Test.Api;

public class CustomerAddressesApiTests(BayaApiFactory factory) : IClassFixture<BayaApiFactory>
{
    private const long TehranCityId = 101;

    // ASCII address line so the DbContext's Persian-digit normalization (Fa2En) can't alter the value
    // between write and read, keeping the decrypt round-trip assertion exact.
    private static object AddressBody(string title, bool isPrimary = false, string addressLine = "Valiasr Street No 10") => new
    {
        title,
        cityId = TehranCityId,
        addressLine,
        postalCode = "1234567890",
        recipientName = "علی",
        recipientPhone = "09120000000",
        isPrimary
    };

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

        var create = await client.PostAsJsonAsync("/api/v1/customer_addresses/create", AddressBody("خانه", isPrimary: true));
        Assert.Equal(HttpStatusCode.OK, create.StatusCode);
        var created = await AuthTestClient.ReadDataAsync(create);
        Assert.True(created.GetProperty("isPrimary").GetBoolean());
        // Geocoded by the IGeocoder mock.
        Assert.False(created.GetProperty("latitude").ValueKind == System.Text.Json.JsonValueKind.Null);
        // The owner's own read returns the decrypted address.
        Assert.Equal("Valiasr Street No 10", created.GetProperty("addressLine").GetString());

        var list = await client.GetAsync("/api/v1/customer_addresses/list");
        var listData = await AuthTestClient.ReadDataAsync(list);
        Assert.Equal(1, listData.GetProperty("total").GetInt32());
        Assert.Equal("Valiasr Street No 10",
            listData.GetProperty("items")[0].GetProperty("addressLine").GetString());
    }

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

        var first = await client.PostAsJsonAsync("/api/v1/customer_addresses/create", AddressBody("خانه", isPrimary: true));
        var firstId = (await AuthTestClient.ReadDataAsync(first)).GetProperty("id").GetInt64();

        var second = await client.PostAsJsonAsync("/api/v1/customer_addresses/create", AddressBody("کار", isPrimary: true));
        var secondId = (await AuthTestClient.ReadDataAsync(second)).GetProperty("id").GetInt64();

        var list = await client.GetAsync("/api/v1/customer_addresses/list");
        var items = (await AuthTestClient.ReadDataAsync(list)).GetProperty("items").EnumerateArray().ToList();

        Assert.Single(items, i => i.GetProperty("isPrimary").GetBoolean());
        Assert.True(Primary(items, secondId));
        Assert.False(Primary(items, firstId));
    }

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

        var create = await client.PostAsJsonAsync("/api/v1/customer_addresses/create",
            AddressBody("خانه", isPrimary: true, addressLine: "NO_GEO unresolved address"));
        var created = await AuthTestClient.ReadDataAsync(create);

        Assert.Equal(System.Text.Json.JsonValueKind.Null, created.GetProperty("latitude").ValueKind);
    }

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

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

        var response = await client.PostAsJsonAsync("/api/v1/customer_addresses/create",
            AddressBody("خانه", addressLine: ""));
        Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
    }

    private static bool Primary(IEnumerable<System.Text.Json.JsonElement> items, long id) =>
        items.Single(i => i.GetProperty("id").GetInt64() == id).GetProperty("isPrimary").GetBoolean();
}
