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

namespace TrackQrApi.Tests;

public class LinkEndpointTests(
    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);

        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 CreateLink_WithValidData_ReturnsCreated()
    {
        // Arrange
        var (token, workspaceId) = await SetupAuthAndWorkspaceAsync("create-link@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // Act
        var response = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://example.com",
            Title = "Example Link"
        });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);
        var result = await response.Content.ReadFromJsonAsync<LinkResponse>();
        result.Should().NotBeNull();
        result!.DestinationUrl.Should().Be("https://example.com");
        result.Title.Should().Be("Example Link");
        result.Slug.Should().NotBeNullOrEmpty();
        result.Slug.Should().HaveLength(7); // Default slug length
        result.Status.Should().Be("Active");
        result.WorkspaceId.Should().Be(workspaceId);
    }

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

        // Act
        var response = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://example.com",
            Slug = "my-custom-slug"
        });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);
        var result = await response.Content.ReadFromJsonAsync<LinkResponse>();
        result!.Slug.Should().Be("my-custom-slug");
    }

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

        await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://example.com",
            Slug = "duplicate-slug"
        });

        // Act
        var response = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://another.com",
            Slug = "duplicate-slug"
        });

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

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

        // Act
        var response = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "not-a-valid-url"
        });

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

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

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

        // Act
        var response = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://example.com",
            ProjectId = project!.Id
        });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);
        var result = await response.Content.ReadFromJsonAsync<LinkResponse>();
        result!.ProjectId.Should().Be(project.Id);
    }

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

        await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links",
            new { DestinationUrl = "https://example1.com" });
        await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links",
            new { DestinationUrl = "https://example2.com" });

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<LinkListResponse>();
        result!.Links.Should().HaveCountGreaterThanOrEqualTo(2);
    }

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

        var projectResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/projects", new { Name = "Filter Project" });
        var project = await projectResponse.Content.ReadFromJsonAsync<ProjectResponse>();

        await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links",
            new { DestinationUrl = "https://in-project.com", ProjectId = project!.Id });
        await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links",
            new { DestinationUrl = "https://no-project.com" });

        // Act
        var response = await _client.GetAsync($"/workspaces/{workspaceId}/links?projectId={project.Id}");

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<LinkListResponse>();
        result!.Links.Should().OnlyContain(l => l.ProjectId == project.Id);
    }

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

        var createResponse = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://example.com",
            Title = "Get Test"
        });
        var created = await createResponse.Content.ReadFromJsonAsync<LinkResponse>();

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

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

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

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

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

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

        var createResponse = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://original.com",
            Title = "Original"
        });
        var created = await createResponse.Content.ReadFromJsonAsync<LinkResponse>();

        // Act
        var response = await _client.PutAsJsonAsync($"/workspaces/{workspaceId}/links/{created!.Id}", new
        {
            DestinationUrl = "https://updated.com",
            Title = "Updated"
        });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<LinkResponse>();
        result!.DestinationUrl.Should().Be("https://updated.com");
        result.Title.Should().Be("Updated");
    }

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

        var createResponse = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://example.com"
        });
        var created = await createResponse.Content.ReadFromJsonAsync<LinkResponse>();

        // Act
        var response = await _client.PutAsJsonAsync($"/workspaces/{workspaceId}/links/{created!.Id}", new
        {
            Status = "Disabled"
        });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<LinkResponse>();
        result!.Status.Should().Be("Disabled");
    }

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

        var createResponse = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://example.com"
        });
        var created = await createResponse.Content.ReadFromJsonAsync<LinkResponse>();
        created!.HasPassword.Should().BeFalse();

        // Act
        var response = await _client.PutAsJsonAsync($"/workspaces/{workspaceId}/links/{created.Id}", new
        {
            Password = "secret123"
        });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<LinkResponse>();
        result!.HasPassword.Should().BeTrue();
    }

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

        var createResponse = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://example.com"
        });
        var created = await createResponse.Content.ReadFromJsonAsync<LinkResponse>();

        await _client.PutAsJsonAsync($"/workspaces/{workspaceId}/links/{created!.Id}", new { Password = "secret123" });

        // Act
        var response = await _client.PutAsJsonAsync($"/workspaces/{workspaceId}/links/{created.Id}", new
        {
            RemovePassword = true
        });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<LinkResponse>();
        result!.HasPassword.Should().BeFalse();
    }

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

        var createResponse = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://example.com"
        });
        var created = await createResponse.Content.ReadFromJsonAsync<LinkResponse>();

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

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

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

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

        // Create link as user1
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token1);
        var createResponse = await _client.PostAsJsonAsync($"/workspaces/{workspaceId1}/links", new
        {
            DestinationUrl = "https://user1.com"
        });
        var created = await createResponse.Content.ReadFromJsonAsync<LinkResponse>();

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

        // Act
        var getResponse = await _client.GetAsync($"/workspaces/{workspaceId1}/links/{created!.Id}");
        var updateResponse =
            await _client.PutAsJsonAsync($"/workspaces/{workspaceId1}/links/{created.Id}", new { Title = "Hacked" });
        var deleteResponse = await _client.DeleteAsync($"/workspaces/{workspaceId1}/links/{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);
    }
}