using System.Net;
using Microsoft.AspNetCore.Mvc.Testing;

namespace CartWise.Web.Tests;

public class ShoppingListAccessControlTests : IClassFixture<CartWiseWebApplicationFactory>
{
    private readonly CartWiseWebApplicationFactory _factory;

    public ShoppingListAccessControlTests(CartWiseWebApplicationFactory factory)
    {
        _factory = factory;
    }

    [Fact]
    public async Task AnonymousUser_IsRedirectedToLoginWhenRequestingList()
    {
        var client = _factory.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false });

        var response = await client.GetAsync("/list");

        Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
        Assert.Contains("/Account/Login", response.Headers.Location?.ToString());
    }

    [Fact]
    public async Task Index_AutoCreatesDefaultListForNewHousehold()
    {
        var client = _factory.CreateClient();
        await WebTestHelpers.RegisterAsync(client, "listuser1@example.com", "List User");
        await WebTestHelpers.CreateHouseholdAsync(client, "List Household");

        var html = await client.GetStringAsync("/list");

        HtmlAssert.Contains("Groceries", html);
    }

    [Fact]
    public async Task AddItem_AppearsOnActiveList()
    {
        var client = _factory.CreateClient();
        await WebTestHelpers.RegisterAsync(client, "listuser2@example.com", "List User 2");
        await WebTestHelpers.CreateHouseholdAsync(client, "Another Household");

        var listHtml = await client.GetStringAsync("/list");
        var token = WebTestHelpers.ExtractAntiForgeryToken(listHtml);

        var form = new Dictionary<string, string>
        {
            ["__RequestVerificationToken"] = token,
            ["NewItem.DisplayName"] = "Milk",
            ["NewItem.Quantity"] = "2",
            ["NewItem.Unit"] = "gal"
        };

        var postResponse = await client.PostAsync("/list/items", new FormUrlEncodedContent(form));
        postResponse.EnsureSuccessStatusCode();

        var updatedHtml = await client.GetStringAsync("/list");
        HtmlAssert.Contains("Milk", updatedHtml);
        HtmlAssert.Contains("2 gal", updatedHtml);
    }

    [Fact]
    public async Task AddItem_WithMissingDisplayName_ShowsValidationErrorAndDoesNotAddItem()
    {
        var client = _factory.CreateClient();
        await WebTestHelpers.RegisterAsync(client, "listuser3@example.com", "List User 3");
        await WebTestHelpers.CreateHouseholdAsync(client, "Third Household");

        var listHtml = await client.GetStringAsync("/list");
        var token = WebTestHelpers.ExtractAntiForgeryToken(listHtml);

        var form = new Dictionary<string, string>
        {
            ["__RequestVerificationToken"] = token,
            ["NewItem.DisplayName"] = string.Empty
        };

        var postResponse = await client.PostAsync("/list/items", new FormUrlEncodedContent(form));
        var body = await postResponse.Content.ReadAsStringAsync();

        Assert.Equal(HttpStatusCode.OK, postResponse.StatusCode);
        Assert.Contains("field-validation-error", body);
    }

    [Fact]
    public async Task EachHousehold_OnlySeesItsOwnListItems()
    {
        var clientA = _factory.CreateClient();
        var clientB = _factory.CreateClient();

        await WebTestHelpers.RegisterAsync(clientA, "listalice@example.com", "List Alice");
        await WebTestHelpers.RegisterAsync(clientB, "listbob@example.com", "List Bob");
        await WebTestHelpers.CreateHouseholdAsync(clientA, "Alice's List Household");
        await WebTestHelpers.CreateHouseholdAsync(clientB, "Bob's List Household");

        var listHtmlA = await clientA.GetStringAsync("/list");
        var tokenA = WebTestHelpers.ExtractAntiForgeryToken(listHtmlA);
        await clientA.PostAsync("/list/items", new FormUrlEncodedContent(new Dictionary<string, string>
        {
            ["__RequestVerificationToken"] = tokenA,
            ["NewItem.DisplayName"] = "Alice Item"
        }));

        var listHtmlB = await clientB.GetStringAsync("/list");
        var tokenB = WebTestHelpers.ExtractAntiForgeryToken(listHtmlB);
        await clientB.PostAsync("/list/items", new FormUrlEncodedContent(new Dictionary<string, string>
        {
            ["__RequestVerificationToken"] = tokenB,
            ["NewItem.DisplayName"] = "Bob Item"
        }));

        var finalA = await clientA.GetStringAsync("/list");
        var finalB = await clientB.GetStringAsync("/list");

        HtmlAssert.Contains("Alice Item", finalA);
        HtmlAssert.DoesNotContain("Bob Item", finalA);

        HtmlAssert.Contains("Bob Item", finalB);
        HtmlAssert.DoesNotContain("Alice Item", finalB);
    }
}
