using System.Net;
using System.Net.Http.Json;
using FluentAssertions;
using TrackQrApi.Features.Auth.Common;

namespace TrackQrApi.Tests;

public class AuthControllerTests(
    ApiWebApplicationFactory factory)
    : IClassFixture<ApiWebApplicationFactory>
{
    private readonly HttpClient _client = factory.CreateClient();

    [Fact]
    public async Task Register_WithValidCredentials_ReturnsTokenAndUser()
    {
        // Arrange
        var request = new { Email = "newuser@example.com", Password = "password123" };

        // Act
        var response = await _client.PostAsJsonAsync("/auth/register", request);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);

        var result = await response.Content.ReadFromJsonAsync<AuthResponse>();
        result.Should().NotBeNull();
        result!.Token.Should().NotBeNullOrEmpty();
        result.User.Email.Should().Be("newuser@example.com");
        result.User.IsVerified.Should().BeFalse();
        result.ExpiresAt.Should().BeAfter(DateTime.UtcNow);
    }

    [Fact]
    public async Task Register_WithDuplicateEmail_ReturnsConflict()
    {
        // Arrange
        var request = new { Email = "duplicate@example.com", Password = "password123" };

        // First registration
        await _client.PostAsJsonAsync("/auth/register", request);

        // Act - try to register again
        var response = await _client.PostAsJsonAsync("/auth/register", request);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Conflict);

        var result = await response.Content.ReadFromJsonAsync<MessageResponse>();
        result.Should().NotBeNull();
        result!.Message.Should().Be("Email already registered");
    }

    [Fact]
    public async Task Register_WithInvalidEmail_ReturnsBadRequest()
    {
        // Arrange
        var request = new { Email = "not-an-email", Password = "password123" };

        // Act
        var response = await _client.PostAsJsonAsync("/auth/register", request);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
    }

    [Fact]
    public async Task Register_WithShortPassword_ReturnsBadRequest()
    {
        // Arrange
        var request = new { Email = "shortpw@example.com", Password = "short" };

        // Act
        var response = await _client.PostAsJsonAsync("/auth/register", request);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
    }

    [Fact]
    public async Task Login_WithValidCredentials_ReturnsToken()
    {
        // Arrange
        var email = "logintest@example.com";
        var password = "password123";

        await _client.PostAsJsonAsync("/auth/register", new { Email = email, Password = password });

        // Act
        var response = await _client.PostAsJsonAsync("/auth/login", new { Email = email, Password = password });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);

        var result = await response.Content.ReadFromJsonAsync<AuthResponse>();
        result.Should().NotBeNull();
        result!.Token.Should().NotBeNullOrEmpty();
        result.User.Email.Should().Be(email);
    }

    [Fact]
    public async Task Login_WithWrongPassword_ReturnsUnauthorized()
    {
        // Arrange
        var email = "wrongpw@example.com";
        await _client.PostAsJsonAsync("/auth/register", new { Email = email, Password = "correctpassword" });

        // Act
        var response = await _client.PostAsJsonAsync("/auth/login", new { Email = email, Password = "wrongpassword" });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);

        var result = await response.Content.ReadFromJsonAsync<MessageResponse>();
        result.Should().NotBeNull();
        result!.Message.Should().Be("Invalid email or password");
    }

    [Fact]
    public async Task Login_WithNonExistentEmail_ReturnsUnauthorized()
    {
        // Arrange
        var request = new { Email = "nonexistent@example.com", Password = "password123" };

        // Act
        var response = await _client.PostAsJsonAsync("/auth/login", request);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);

        var result = await response.Content.ReadFromJsonAsync<MessageResponse>();
        result.Should().NotBeNull();
        result!.Message.Should().Be("Invalid email or password");
    }

    [Fact]
    public async Task ForgotPassword_WithAnyEmail_ReturnsSuccessMessage()
    {
        // Arrange - using a non-existent email to verify we don't leak info
        var request = new { Email = "anyone@example.com" };

        // Act
        var response = await _client.PostAsJsonAsync("/auth/forgot", request);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);

        var result = await response.Content.ReadFromJsonAsync<MessageResponse>();
        result.Should().NotBeNull();
        result!.Message.Should().Be("If the email exists, a reset link will be sent");
    }

    [Fact]
    public async Task ForgotPassword_WithExistingEmail_ReturnsSuccessMessage()
    {
        // Arrange
        var email = "forgotpw@example.com";
        await _client.PostAsJsonAsync("/auth/register", new { Email = email, Password = "password123" });

        // Act
        var response = await _client.PostAsJsonAsync("/auth/forgot", new { Email = email });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);

        var result = await response.Content.ReadFromJsonAsync<MessageResponse>();
        result.Should().NotBeNull();
        result!.Message.Should().Be("If the email exists, a reset link will be sent");
    }

    [Fact]
    public async Task ResetPassword_WithInvalidToken_ReturnsBadRequest()
    {
        // Arrange
        var request = new { Token = "some-token", NewPassword = "newpassword123" };

        // Act
        var response = await _client.PostAsJsonAsync("/auth/reset", request);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.BadRequest);

        var result = await response.Content.ReadFromJsonAsync<MessageResponse>();
        result.Should().NotBeNull();
        result!.Message.Should().Be("Invalid or expired reset token");
    }

    [Fact]
    public async Task Register_CreatesDefaultWorkspace()
    {
        // Arrange
        var request = new { Email = "workspace@example.com", Password = "password123" };

        // Act
        var response = await _client.PostAsJsonAsync("/auth/register", request);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);

        var result = await response.Content.ReadFromJsonAsync<AuthResponse>();
        result.Should().NotBeNull();
        result!.User.Id.Should().NotBeEmpty();
        // The workspace is created but not returned in auth response
        // This could be verified with a separate workspaces endpoint test
    }

    [Fact]
    public async Task Login_IsCaseInsensitive()
    {
        // Arrange
        var email = "CaseTEST@Example.COM";
        var password = "password123";

        await _client.PostAsJsonAsync("/auth/register", new { Email = email, Password = password });

        // Act - login with different casing
        var response = await _client.PostAsJsonAsync("/auth/login",
            new { Email = "casetest@example.com", Password = password });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);

        var result = await response.Content.ReadFromJsonAsync<AuthResponse>();
        result!.User.Email.Should().Be("casetest@example.com");
    }
}