using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using TrackQrApi.Features.Auth.Common;
using TrackQrApi.Features.Links.Common;
using TrackQrApi.Features.Workspaces.Common;

namespace TrackQrApi.Tests;

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

    private readonly HttpClient _noRedirectClient = factory.CreateClient(new WebApplicationFactoryClientOptions
    {
        AllowAutoRedirect = false
    });

    // Create a client that doesn't follow redirects

    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);
    }

    private async Task<LinkResponse> CreateLinkAsync(Guid workspaceId, string destinationUrl, string? slug = null,
        string? password = null)
    {
        var createResponse = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = destinationUrl,
            Slug = slug
        });
        var link = await createResponse.Content.ReadFromJsonAsync<LinkResponse>();

        if (password != null)
        {
            await _client.PutAsJsonAsync($"/workspaces/{workspaceId}/links/{link!.Id}", new { Password = password });
            var updated = await _client.GetAsync($"/workspaces/{workspaceId}/links/{link.Id}");
            return (await updated.Content.ReadFromJsonAsync<LinkResponse>())!;
        }

        return link!;
    }

    [Fact]
    public async Task Redirect_WithValidSlug_Returns302Redirect()
    {
        // Arrange
        var (_, workspaceId) = await SetupAuthAndWorkspaceAsync("redirect-valid@example.com");
        var link = await CreateLinkAsync(workspaceId, "https://example.com", "test-redirect");

        // Act - Use no-redirect client to capture the redirect
        var response = await _noRedirectClient.GetAsync($"/{link.Slug}");

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Redirect);
        response.Headers.Location.Should().NotBeNull();
        response.Headers.Location!.ToString().Should().StartWith("https://example.com");
    }

    [Fact]
    public async Task Redirect_WithNonExistentSlug_Returns404()
    {
        // Act
        var response = await _client.GetAsync("/nonexistent-slug-12345");

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

    [Fact]
    public async Task Redirect_WithDisabledLink_Returns404()
    {
        // Arrange
        var (_, workspaceId) = await SetupAuthAndWorkspaceAsync("redirect-disabled@example.com");
        var link = await CreateLinkAsync(workspaceId, "https://example.com", "disabled-link");

        // Disable the link
        await _client.PutAsJsonAsync($"/workspaces/{workspaceId}/links/{link.Id}", new { Status = "Disabled" });

        // Act
        var response = await _client.GetAsync($"/{link.Slug}");

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

    [Fact]
    public async Task Redirect_WithExpiredLink_Returns410()
    {
        // Arrange
        var (_, workspaceId) = await SetupAuthAndWorkspaceAsync("redirect-expired@example.com");
        var link = await CreateLinkAsync(workspaceId, "https://example.com", "expired-link");

        // Set expiration to the past
        await _client.PutAsJsonAsync($"/workspaces/{workspaceId}/links/{link.Id}", new
        {
            ExpiresAt = DateTime.UtcNow.AddDays(-1)
        });

        // Act
        var response = await _client.GetAsync($"/{link.Slug}");

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

    [Fact]
    public async Task Redirect_WithPasswordProtectedLink_Returns401()
    {
        // Arrange
        var (_, workspaceId) = await SetupAuthAndWorkspaceAsync("redirect-password@example.com");
        var link = await CreateLinkAsync(workspaceId, "https://example.com", "password-link", "secret123");

        // Act
        var response = await _client.GetAsync($"/{link.Slug}");

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
        response.Headers.Contains("X-Password-Required").Should().BeTrue();
    }

    [Fact]
    public async Task PasswordRedirect_WithCorrectPassword_Returns302Redirect()
    {
        // Arrange
        var (_, workspaceId) = await SetupAuthAndWorkspaceAsync("redirect-pass-ok@example.com");
        var link = await CreateLinkAsync(workspaceId, "https://example.com", "password-ok-link", "secret123");

        // Act
        var response = await _noRedirectClient.PostAsJsonAsync($"/{link.Slug}", new { Password = "secret123" });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Redirect);
        response.Headers.Location!.ToString().Should().StartWith("https://example.com");
    }

    [Fact]
    public async Task PasswordRedirect_WithWrongPassword_Returns401()
    {
        // Arrange
        var (_, workspaceId) = await SetupAuthAndWorkspaceAsync("redirect-pass-wrong@example.com");
        var link = await CreateLinkAsync(workspaceId, "https://example.com", "password-wrong-link", "secret123");

        // Act
        var response = await _client.PostAsJsonAsync($"/{link.Slug}", new { Password = "wrongpassword" });

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

    [Fact]
    public async Task PasswordRedirect_WithEmptyPassword_Returns400()
    {
        // Arrange
        var (_, workspaceId) = await SetupAuthAndWorkspaceAsync("redirect-pass-empty@example.com");
        var link = await CreateLinkAsync(workspaceId, "https://example.com", "password-empty-link", "secret123");

        // Act
        var response = await _client.PostAsJsonAsync($"/{link.Slug}", new { Password = "" });

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

    [Fact]
    public async Task PasswordRedirect_NonProtectedLink_RedirectsAnyway()
    {
        // Arrange
        var (_, workspaceId) = await SetupAuthAndWorkspaceAsync("redirect-no-pass@example.com");
        var link = await CreateLinkAsync(workspaceId, "https://example.com", "no-password-link");

        // Act - POST to non-password protected link
        var response = await _noRedirectClient.PostAsJsonAsync($"/{link.Slug}", new { Password = "anything" });

        // Assert - Should still redirect since link doesn't require password
        response.StatusCode.Should().Be(HttpStatusCode.Redirect);
    }

    [Fact]
    public async Task Redirect_DoesNotRequireAuthentication()
    {
        // Arrange
        var (_, workspaceId) = await SetupAuthAndWorkspaceAsync("redirect-anon@example.com");
        var link = await CreateLinkAsync(workspaceId, "https://example.com", "anon-redirect-link");

        // Remove auth header
        _noRedirectClient.DefaultRequestHeaders.Authorization = null;

        // Act
        var response = await _noRedirectClient.GetAsync($"/{link.Slug}");

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