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

namespace Baya.Test.Api;

public class NurseVariantsApiTests(BayaApiFactory factory) : IClassFixture<BayaApiFactory>
{
    private const long ElderlyCategoryId = 1;

    private static async Task SetUpNurseAsync(BayaApiFactory factory, HttpClient client, string phone)
    {
        await ProfileTestClient.AuthenticateAsync(factory, client, phone, "nurse");
        await client.PostAsJsonAsync("/api/v1/nurse_profiles/upsert",
            new { bio = "b", yearsOfExperience = 5, educationLevel = "", educationField = "", specializationsJson = "[]" });
    }

    [Fact]
    public async Task Variant_FullLifecycle_BuildDuplicateMissingRequiredListDeactivateTenancy()
    {
        // --- Admin builds the required dimension for the Elderly category ---
        var admin = factory.CreateClient();
        await AdminTestClient.AuthenticateAsync(factory, admin, "09132000001");

        var groupResp = await admin.PostAsJsonAsync("/api/v1/admin_catalog/create_option_group",
            new { serviceCategoryId = ElderlyCategoryId, nameFa = "نوع شیفت", nameEn = "Shift type", isRequired = true, sortOrder = 1 });
        var groupId = (await AuthTestClient.ReadDataAsync(groupResp)).GetProperty("id").GetInt64();

        var valResp = await admin.PostAsJsonAsync("/api/v1/admin_catalog/create_option_value",
            new { optionGroupId = groupId, nameFa = "شبانه‌روزی", nameEn = "Live-in", sortOrder = 1 });
        var liveInId = (await AuthTestClient.ReadDataAsync(valResp)).GetProperty("id").GetInt64();

        // --- Nurse builds a valid variant ---
        var nurse = factory.CreateClient();
        await SetUpNurseAsync(factory, nurse, "09132000002");

        object CreatePayload(long valueId) => new
        {
            serviceCategoryId = ElderlyCategoryId,
            options = new[] { new { optionGroupId = groupId, optionValueId = valueId } },
            price = "8000000",
            priceUnit = "per_24h"
        };

        var create = await nurse.PostAsJsonAsync("/api/v1/nurse_variants/create", CreatePayload(liveInId));
        Assert.Equal(HttpStatusCode.OK, create.StatusCode);
        var created = await AuthTestClient.ReadDataAsync(create);
        var variantId = created.GetProperty("id").GetInt64();
        Assert.True(created.GetProperty("isActive").GetBoolean());
        Assert.Equal("8000000", created.GetProperty("price").GetString());
        // The DbContext normalises the Persian ZWNJ (نیم‌فاصله) to a space platform-wide, so assert on a
        // ZWNJ-agnostic substring of the auto-generated display name (category + chosen value label).
        var displayName = created.GetProperty("displayName").GetString();
        Assert.Contains("مراقبت از سالمند", displayName);
        Assert.Contains("شبانه", displayName);

        // --- Public (anonymous) sees the active variant ---
        var anon = factory.CreateClient();
        var publicGet = await anon.GetAsync($"/api/v1/nurse_variants/get/{variantId}");
        Assert.Equal(HttpStatusCode.OK, publicGet.StatusCode);
        Assert.Equal("8000000", (await AuthTestClient.ReadDataAsync(publicGet)).GetProperty("price").GetString());

        // --- Duplicate identical listing → 409 (clean, not a 500) ---
        var duplicate = await nurse.PostAsJsonAsync("/api/v1/nurse_variants/create", CreatePayload(liveInId));
        Assert.Equal(HttpStatusCode.Conflict, duplicate.StatusCode);

        // --- Missing the required dimension → 400 ---
        var missing = await nurse.PostAsJsonAsync("/api/v1/nurse_variants/create",
            new { serviceCategoryId = ElderlyCategoryId, options = Array.Empty<object>(), price = "5000000", priceUnit = "per_day" });
        Assert.Equal(HttpStatusCode.BadRequest, missing.StatusCode);

        // --- List shows the one active variant ---
        var listActive = await AuthTestClient.ReadDataAsync(await nurse.GetAsync("/api/v1/nurse_variants/list"));
        Assert.Equal(1, listActive.GetProperty("total").GetInt32());

        // --- Deactivate (never delete); it stays in the list, flagged inactive ---
        var deactivate = await nurse.PostAsJsonAsync($"/api/v1/nurse_variants/set_active/{variantId}", new { isActive = false });
        Assert.Equal(HttpStatusCode.OK, deactivate.StatusCode);

        var listAfter = await AuthTestClient.ReadDataAsync(await nurse.GetAsync("/api/v1/nurse_variants/list"));
        Assert.Equal(1, listAfter.GetProperty("total").GetInt32());
        var row = listAfter.GetProperty("items").EnumerateArray().Single(v => v.GetProperty("id").GetInt64() == variantId);
        Assert.False(row.GetProperty("isActive").GetBoolean());

        // --- A deactivated variant drops out of the public view (404) ---
        var publicGetAfter = await anon.GetAsync($"/api/v1/nurse_variants/get/{variantId}");
        Assert.Equal(HttpStatusCode.NotFound, publicGetAfter.StatusCode);

        // --- Tenancy: a different nurse cannot edit it → 404 (existence not leaked) ---
        var otherNurse = factory.CreateClient();
        await SetUpNurseAsync(factory, otherNurse, "09132000003");
        var tenancy = await otherNurse.PostAsJsonAsync($"/api/v1/nurse_variants/update/{variantId}",
            new { price = "9000000", priceUnit = "per_day" });
        Assert.Equal(HttpStatusCode.NotFound, tenancy.StatusCode);
    }

    [Fact]
    public async Task Create_Unauthenticated_Returns401()
    {
        var client = factory.CreateClient();
        var response = await client.PostAsJsonAsync("/api/v1/nurse_variants/create",
            new { serviceCategoryId = ElderlyCategoryId, options = Array.Empty<object>(), price = "8000000", priceUnit = "per_24h" });
        Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
    }

    [Fact]
    public async Task Create_InvalidPrice_Returns400()
    {
        var client = factory.CreateClient();
        await SetUpNurseAsync(factory, client, "09132000004");

        var response = await client.PostAsJsonAsync("/api/v1/nurse_variants/create",
            new { serviceCategoryId = ElderlyCategoryId, options = Array.Empty<object>(), price = "-5", priceUnit = "per_24h" });
        Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
    }
}
