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

namespace TrackQrApi.Tests;

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

    private async Task<(string Token, Guid WorkspaceId)> GetAuthAndWorkspaceAsync(string email,
        bool upgradeToPro = true)
    {
        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 result = await response.Content.ReadFromJsonAsync<AuthResponse>();
        var token = result!.Token;

        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        var workspacesResponse = await _client.GetAsync("/workspaces");
        var workspaces = await workspacesResponse.Content.ReadFromJsonAsync<WorkspaceListResponse>();
        var workspaceId = workspaces!.Workspaces.First().Id;

        // Upgrade to Pro plan for domain tests (Free plan doesn't allow custom domains)
        if (upgradeToPro) await factory.UpgradeWorkspaceToPro(workspaceId);

        return (token, workspaceId);
    }

    [Fact]
    public async Task AddDomain_WithValidHostname_ReturnsCreated()
    {
        // Arrange
        var (token, workspaceId) = await GetAuthAndWorkspaceAsync("add-domain@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // Act
        var response =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/domains", new { Hostname = "example.com" });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);
        var result = await response.Content.ReadFromJsonAsync<DomainResponse>();
        result.Should().NotBeNull();
        result!.Hostname.Should().Be("example.com");
        result.Status.Should().Be("Pending");
        result.VerificationToken.Should().NotBeNullOrEmpty();
        result.VerificationRecord.Should().Contain("_trakqr-verification");
    }

    [Fact]
    public async Task AddDomain_WithEmptyHostname_ReturnsBadRequest()
    {
        // Arrange
        var (token, workspaceId) = await GetAuthAndWorkspaceAsync("add-domain-invalid@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

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

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

    [Fact]
    public async Task AddDomain_DuplicateHostname_ReturnsConflict()
    {
        // Arrange
        var (token, workspaceId) = await GetAuthAndWorkspaceAsync("add-domain-dup@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/domains", new { Hostname = "duplicate.com" });

        // Act
        var response =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/domains", new { Hostname = "duplicate.com" });

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

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

        await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/domains", new { Hostname = "list-test.com" });

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<DomainListResponse>();
        result.Should().NotBeNull();
        result!.Domains.Should().Contain(d => d.Hostname == "list-test.com");
    }

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

        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/domains", new { Hostname = "get-test.com" });
        var created = await createResponse.Content.ReadFromJsonAsync<DomainResponse>();

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<DomainResponse>();
        result!.Id.Should().Be(created.Id);
        result.Hostname.Should().Be("get-test.com");
    }

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

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

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

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

        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/domains", new { Hostname = "to-delete.com" });
        var created = await createResponse.Content.ReadFromJsonAsync<DomainResponse>();

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

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

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

    [Fact]
    public async Task VerifyDomain_WithUnverifiedDomain_ReturnsNotVerified()
    {
        // Arrange
        var (token, workspaceId) = await GetAuthAndWorkspaceAsync("verify-domain@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/domains", new { Hostname = "unverified.com" });
        var created = await createResponse.Content.ReadFromJsonAsync<DomainResponse>();

        // Act
        var response =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/domains/{created!.Id}/verify", new { });

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

    [Fact]
    public async Task VerifyDomain_WithVerifiedPrefix_ReturnsVerified()
    {
        // Arrange
        var (token, workspaceId) = await GetAuthAndWorkspaceAsync("verify-domain-ok@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // The verification mock accepts domains starting with "verified-"
        var createResponse = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/domains",
            new { Hostname = "verified-test.com" });
        var created = await createResponse.Content.ReadFromJsonAsync<DomainResponse>();

        // Act
        var response =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/domains/{created!.Id}/verify", new { });

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

    [Fact]
    public async Task Domain_CannotAccessOtherUsersWorkspace()
    {
        // Arrange
        var (token1, workspaceId1) = await GetAuthAndWorkspaceAsync("domain-user1@example.com");
        var (token2, _) = await GetAuthAndWorkspaceAsync("domain-user2@example.com");

        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token1);
        var createResponse = await _client.PostAsJsonAsync($"/workspaces/{workspaceId1}/domains",
            new { Hostname = "user1-domain.com" });
        var created = await createResponse.Content.ReadFromJsonAsync<DomainResponse>();

        // Act - Try to access as user2
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token2);
        var getResponse = await _client.GetAsync($"/workspaces/{workspaceId1}/domains/{created!.Id}");
        var deleteResponse = await _client.DeleteAsync($"/workspaces/{workspaceId1}/domains/{created.Id}");

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