using System.Net;
using System.Net.Http.Json;
using FluentAssertions;
using ColaFlow.Modules.ProjectManagement.IntegrationTests.Infrastructure;
using ColaFlow.Modules.ProjectManagement.Application.DTOs;

namespace ColaFlow.Modules.ProjectManagement.IntegrationTests;

/// <summary>
/// CRITICAL: Multi-tenant isolation tests
/// These tests verify that tenant data is properly isolated
/// </summary>
public class MultiTenantIsolationTests : IClassFixture<PMWebApplicationFactory>
{
    private readonly PMWebApplicationFactory _factory;
    private readonly HttpClient _client;

    // Test tenant and user IDs
    private readonly Guid _tenant1Id = Guid.NewGuid();
    private readonly Guid _tenant2Id = Guid.NewGuid();
    private readonly Guid _user1Id = Guid.NewGuid();
    private readonly Guid _user2Id = Guid.NewGuid();

    public MultiTenantIsolationTests(PMWebApplicationFactory factory)
    {
        _factory = factory;
        _client = _factory.CreateClient();
    }

    [Fact]
    public async Task Project_Should_Be_Isolated_By_TenantId()
    {
        // Arrange: Tenant 1 creates a project
        var tenant1Token = TestAuthHelper.GenerateJwtToken(_user1Id, _tenant1Id, "tenant1", "user1@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant1Token);

        var createRequest = new
        {
            Name = "Tenant 1 Project",
            Key = "T1P",
            Description = "This is tenant 1's project"
        };

        var createResponse = await _client.PostAsJsonAsync("/api/v1/projects", createRequest);
        createResponse.EnsureSuccessStatusCode();

        var project = await createResponse.Content.ReadFromJsonAsync<ProjectDto>();
        project.Should().NotBeNull();
        project!.Name.Should().Be("Tenant 1 Project");

        // Act: Tenant 2 tries to access Tenant 1's project
        var tenant2Token = TestAuthHelper.GenerateJwtToken(_user2Id, _tenant2Id, "tenant2", "user2@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant2Token);

        var getResponse = await _client.GetAsync($"/api/v1/projects/{project.Id}");

        // Assert: Should return 404 (resource not found due to tenant filter)
        getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }

    [Fact]
    public async Task Tenant_Cannot_List_Other_Tenants_Projects()
    {
        // Arrange: Tenant 1 creates a project
        var tenant1Token = TestAuthHelper.GenerateJwtToken(_user1Id, _tenant1Id, "tenant1", "user1@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant1Token);

        await _client.PostAsJsonAsync("/api/v1/projects", new
        {
            Name = "Tenant 1 Project A",
            Key = "T1PA",
            Description = "First project"
        });

        await _client.PostAsJsonAsync("/api/v1/projects", new
        {
            Name = "Tenant 1 Project B",
            Key = "T1PB",
            Description = "Second project"
        });

        // Arrange: Tenant 2 creates a project
        var tenant2Token = TestAuthHelper.GenerateJwtToken(_user2Id, _tenant2Id, "tenant2", "user2@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant2Token);

        await _client.PostAsJsonAsync("/api/v1/projects", new
        {
            Name = "Tenant 2 Project",
            Key = "T2P",
            Description = "Tenant 2's project"
        });

        // Act: Tenant 2 lists projects
        var listResponse = await _client.GetAsync("/api/v1/projects");
        listResponse.EnsureSuccessStatusCode();

        var projects = await listResponse.Content.ReadFromJsonAsync<List<ProjectDto>>();

        // Assert: Should only see Tenant 2's project
        projects.Should().NotBeNull();
        projects!.Count.Should().Be(1);
        projects[0].Name.Should().Be("Tenant 2 Project");
    }

    [Fact]
    public async Task Epic_Should_Be_Isolated_By_TenantId()
    {
        // Arrange: Tenant 1 creates a project with an epic
        var tenant1Token = TestAuthHelper.GenerateJwtToken(_user1Id, _tenant1Id, "tenant1", "user1@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant1Token);

        // Create project
        var projectResponse = await _client.PostAsJsonAsync("/api/v1/projects", new
        {
            Name = "Tenant 1 Project",
            Key = "T1P",
            Description = "Test project"
        });
        var project = await projectResponse.Content.ReadFromJsonAsync<ProjectDto>();

        // Create epic
        var epicResponse = await _client.PostAsJsonAsync("/api/v1/epics", new
        {
            ProjectId = project!.Id,
            Name = "Tenant 1 Epic",
            Description = "Test epic",
            CreatedBy = _user1Id
        });
        epicResponse.EnsureSuccessStatusCode();
        var epic = await epicResponse.Content.ReadFromJsonAsync<EpicDto>();

        // Act: Tenant 2 tries to access Tenant 1's epic
        var tenant2Token = TestAuthHelper.GenerateJwtToken(_user2Id, _tenant2Id, "tenant2", "user2@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant2Token);

        var getResponse = await _client.GetAsync($"/api/v1/epics/{epic!.Id}");

        // Assert: Should return 404
        getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }

    [Fact]
    public async Task Story_Should_Be_Isolated_By_TenantId()
    {
        // Arrange: Tenant 1 creates project → epic → story
        var tenant1Token = TestAuthHelper.GenerateJwtToken(_user1Id, _tenant1Id, "tenant1", "user1@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant1Token);

        // Create project
        var projectResponse = await _client.PostAsJsonAsync("/api/v1/projects", new
        {
            Name = "Tenant 1 Project",
            Key = "T1P",
            Description = "Test project"
        });
        var project = await projectResponse.Content.ReadFromJsonAsync<ProjectDto>();

        // Create epic
        var epicResponse = await _client.PostAsJsonAsync("/api/v1/epics", new
        {
            ProjectId = project!.Id,
            Name = "Tenant 1 Epic",
            Description = "Test epic",
            CreatedBy = _user1Id
        });
        var epic = await epicResponse.Content.ReadFromJsonAsync<EpicDto>();

        // Create story
        var storyResponse = await _client.PostAsJsonAsync("/api/v1/stories", new
        {
            EpicId = epic!.Id,
            Title = "Tenant 1 Story",
            Description = "Test story",
            Priority = "Medium",
            CreatedBy = _user1Id
        });
        storyResponse.EnsureSuccessStatusCode();
        var story = await storyResponse.Content.ReadFromJsonAsync<StoryDto>();

        // Act: Tenant 2 tries to access Tenant 1's story
        var tenant2Token = TestAuthHelper.GenerateJwtToken(_user2Id, _tenant2Id, "tenant2", "user2@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant2Token);

        var getResponse = await _client.GetAsync($"/api/v1/stories/{story!.Id}");

        // Assert: Should return 404
        getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }

    [Fact]
    public async Task Task_Should_Be_Isolated_By_TenantId()
    {
        // Arrange: Tenant 1 creates project → epic → story → task
        var tenant1Token = TestAuthHelper.GenerateJwtToken(_user1Id, _tenant1Id, "tenant1", "user1@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant1Token);

        // Create project
        var projectResponse = await _client.PostAsJsonAsync("/api/v1/projects", new
        {
            Name = "Tenant 1 Project",
            Key = "T1P",
            Description = "Test project"
        });
        var project = await projectResponse.Content.ReadFromJsonAsync<ProjectDto>();

        // Create epic
        var epicResponse = await _client.PostAsJsonAsync("/api/v1/epics", new
        {
            ProjectId = project!.Id,
            Name = "Tenant 1 Epic",
            Description = "Test epic",
            CreatedBy = _user1Id
        });
        var epic = await epicResponse.Content.ReadFromJsonAsync<EpicDto>();

        // Create story
        var storyResponse = await _client.PostAsJsonAsync("/api/v1/stories", new
        {
            EpicId = epic!.Id,
            Title = "Tenant 1 Story",
            Description = "Test story",
            Priority = "Medium",
            CreatedBy = _user1Id
        });
        var story = await storyResponse.Content.ReadFromJsonAsync<StoryDto>();

        // Create task
        var taskResponse = await _client.PostAsJsonAsync("/api/v1/tasks", new
        {
            StoryId = story!.Id,
            Title = "Tenant 1 Task",
            Description = "Test task",
            Priority = "Medium",
            CreatedBy = _user1Id
        });
        taskResponse.EnsureSuccessStatusCode();
        var task = await taskResponse.Content.ReadFromJsonAsync<TaskDto>();

        // Act: Tenant 2 tries to access Tenant 1's task
        var tenant2Token = TestAuthHelper.GenerateJwtToken(_user2Id, _tenant2Id, "tenant2", "user2@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant2Token);

        var getResponse = await _client.GetAsync($"/api/v1/tasks/{task!.Id}");

        // Assert: Should return 404
        getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }

    [Fact]
    public async Task Tenant_Cannot_Update_Other_Tenants_Project()
    {
        // Arrange: Tenant 1 creates a project
        var tenant1Token = TestAuthHelper.GenerateJwtToken(_user1Id, _tenant1Id, "tenant1", "user1@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant1Token);

        var createResponse = await _client.PostAsJsonAsync("/api/v1/projects", new
        {
            Name = "Tenant 1 Project",
            Key = "T1P",
            Description = "Original description"
        });
        var project = await createResponse.Content.ReadFromJsonAsync<ProjectDto>();

        // Act: Tenant 2 tries to update Tenant 1's project
        var tenant2Token = TestAuthHelper.GenerateJwtToken(_user2Id, _tenant2Id, "tenant2", "user2@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant2Token);

        var updateResponse = await _client.PutAsJsonAsync($"/api/v1/projects/{project!.Id}", new
        {
            Name = "Hacked Project Name",
            Description = "Malicious update"
        });

        // Assert: Should return 404 (not 403, because tenant filter makes it invisible)
        updateResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }

    [Fact]
    public async Task Tenant_Cannot_Delete_Other_Tenants_Project()
    {
        // Arrange: Tenant 1 creates a project
        var tenant1Token = TestAuthHelper.GenerateJwtToken(_user1Id, _tenant1Id, "tenant1", "user1@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant1Token);

        var createResponse = await _client.PostAsJsonAsync("/api/v1/projects", new
        {
            Name = "Tenant 1 Project",
            Key = "T1P",
            Description = "Important project"
        });
        var project = await createResponse.Content.ReadFromJsonAsync<ProjectDto>();

        // Act: Tenant 2 tries to delete Tenant 1's project
        var tenant2Token = TestAuthHelper.GenerateJwtToken(_user2Id, _tenant2Id, "tenant2", "user2@test.com");
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant2Token);

        var deleteResponse = await _client.DeleteAsync($"/api/v1/projects/{project!.Id}");

        // Assert: Should return 404
        deleteResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);

        // Verify project still exists for Tenant 1
        _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tenant1Token);
        var verifyResponse = await _client.GetAsync($"/api/v1/projects/{project.Id}");
        verifyResponse.StatusCode.Should().Be(HttpStatusCode.OK);
    }
}
