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

namespace TrackQrApi.Tests;

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

    private async Task<(string Token, Guid WorkspaceId)> SetupAuthAndWorkspaceAsync(string email)
    {
        var response = await _client.PostAsJsonAsync("/auth/register", new { Email = email, Password = "password123" });
        if (response.StatusCode == HttpStatusCode.Conflict)
            response = await _client.PostAsJsonAsync("/auth/login", new { Email = email, Password = "password123" });
        var authResult = await response.Content.ReadFromJsonAsync<AuthResponse>();
        var token = authResult!.Token;

        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // Get the default workspace
        var wsResponse = await _client.GetAsync("/workspaces");
        var wsResult = await wsResponse.Content.ReadFromJsonAsync<WorkspaceListResponse>();
        var workspaceId = wsResult!.Workspaces.First().Id;

        return (token, workspaceId);
    }

    [Fact]
    public async Task ListProjects_WithValidWorkspace_ReturnsProjects()
    {
        // Arrange
        var (token, workspaceId) = await SetupAuthAndWorkspaceAsync("list-proj@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // Act
        var response = await _client.GetAsync($"/workspaces/{workspaceId}/projects");

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<ProjectListResponse>();
        result.Should().NotBeNull();
    }

    [Fact]
    public async Task ListProjects_WithInvalidWorkspace_ReturnsNotFound()
    {
        // Arrange
        var (token, _) = await SetupAuthAndWorkspaceAsync("list-proj-invalid@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // Act
        var response = await _client.GetAsync($"/workspaces/{Guid.NewGuid()}/projects");

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

    [Fact]
    public async Task CreateProject_WithValidData_ReturnsCreated()
    {
        // Arrange
        var (token, workspaceId) = await SetupAuthAndWorkspaceAsync("create-proj@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // Act
        var response =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/projects", new { Name = "Test Project" });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);
        var result = await response.Content.ReadFromJsonAsync<ProjectResponse>();
        result.Should().NotBeNull();
        result!.Name.Should().Be("Test Project");
        result.WorkspaceId.Should().Be(workspaceId);
    }

    [Fact]
    public async Task CreateProject_WithEmptyName_ReturnsBadRequest()
    {
        // Arrange
        var (token, workspaceId) = await SetupAuthAndWorkspaceAsync("create-proj-invalid@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // Act
        var response = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/projects", new { Name = "" });

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

    [Fact]
    public async Task GetProject_WithValidId_ReturnsProject()
    {
        // Arrange
        var (token, workspaceId) = await SetupAuthAndWorkspaceAsync("get-proj@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/projects", new { Name = "Get Test" });
        var created = await createResponse.Content.ReadFromJsonAsync<ProjectResponse>();

        // Act
        var response = await _client.GetAsync($"/workspaces/{workspaceId}/projects/{created!.Id}");

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<ProjectResponse>();
        result!.Id.Should().Be(created.Id);
        result.Name.Should().Be("Get Test");
    }

    [Fact]
    public async Task GetProject_WithInvalidId_ReturnsNotFound()
    {
        // Arrange
        var (token, workspaceId) = await SetupAuthAndWorkspaceAsync("get-proj-invalid@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // Act
        var response = await _client.GetAsync($"/workspaces/{workspaceId}/projects/{Guid.NewGuid()}");

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

    [Fact]
    public async Task UpdateProject_WithValidData_ReturnsUpdated()
    {
        // Arrange
        var (token, workspaceId) = await SetupAuthAndWorkspaceAsync("update-proj@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/projects", new { Name = "Original" });
        var created = await createResponse.Content.ReadFromJsonAsync<ProjectResponse>();

        // Act
        var response = await _client.PutAsJsonAsync($"/workspaces/{workspaceId}/projects/{created!.Id}",
            new { Name = "Updated" });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<ProjectResponse>();
        result!.Name.Should().Be("Updated");
    }

    [Fact]
    public async Task DeleteProject_WithValidId_ReturnsSuccess()
    {
        // Arrange
        var (token, workspaceId) = await SetupAuthAndWorkspaceAsync("delete-proj@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/projects", new { Name = "To Delete" });
        var created = await createResponse.Content.ReadFromJsonAsync<ProjectResponse>();

        // Act
        var response = await _client.DeleteAsync($"/workspaces/{workspaceId}/projects/{created!.Id}");

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

        // Verify it's deleted
        var getResponse = await _client.GetAsync($"/workspaces/{workspaceId}/projects/{created.Id}");
        getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }

    [Fact]
    public async Task Project_CannotAccessOtherUsersProject()
    {
        // Arrange - Create two users
        var (token1, workspaceId1) = await SetupAuthAndWorkspaceAsync("user1-proj@example.com");
        var (token2, _) = await SetupAuthAndWorkspaceAsync("user2-proj@example.com");

        // Create project as user1
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token1);
        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId1}/projects", new { Name = "User1 Project" });
        var created = await createResponse.Content.ReadFromJsonAsync<ProjectResponse>();

        // Try to access as user2
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token2);

        // Act
        var getResponse = await _client.GetAsync($"/workspaces/{workspaceId1}/projects/{created!.Id}");
        var updateResponse = await _client.PutAsJsonAsync($"/workspaces/{workspaceId1}/projects/{created.Id}",
            new { Name = "Hacked" });
        var deleteResponse = await _client.DeleteAsync($"/workspaces/{workspaceId1}/projects/{created.Id}");

        // Assert - All should return NotFound (not exposing existence)
        getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
        updateResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
        deleteResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }
}