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.QRCodes.Common;
using TrackQrApi.Features.Workspaces.Common;

namespace TrackQrApi.Tests;

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

    private async Task<LinkResponse> CreateLinkAsync(Guid workspaceId, string slug)
    {
        var createResponse = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/links", new
        {
            DestinationUrl = "https://example.com",
            Slug = slug
        });
        return (await createResponse.Content.ReadFromJsonAsync<LinkResponse>())!;
    }

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

        var link = await CreateLinkAsync(workspaceId, "qr-create-link");

        // Act
        var response = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/qrcodes", new
        {
            ShortLinkId = link.Id
        });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);
        var result = await response.Content.ReadFromJsonAsync<QRCodeResponse>();
        result.Should().NotBeNull();
        result!.ShortLinkId.Should().Be(link.Id);
        result.ShortLinkSlug.Should().Be(link.Slug);
        result.Style.Should().NotBeNull();
        result.Style.ForegroundColor.Should().Be("#000000");
        result.Style.BackgroundColor.Should().Be("#FFFFFF");
    }

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

        var link = await CreateLinkAsync(workspaceId, "qr-style-link");

        // Act
        var response = await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/qrcodes", new
        {
            ShortLinkId = link.Id,
            Style = new
            {
                ForegroundColor = "#FF0000",
                BackgroundColor = "#00FF00",
                ErrorCorrectionLevel = "H"
            }
        });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);
        var result = await response.Content.ReadFromJsonAsync<QRCodeResponse>();
        result!.Style.ForegroundColor.Should().Be("#FF0000");
        result.Style.BackgroundColor.Should().Be("#00FF00");
        result.Style.ErrorCorrectionLevel.Should().Be("H");
    }

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

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

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

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

        var link = await CreateLinkAsync(workspaceId, "qr-list-link");
        await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/qrcodes", new { ShortLinkId = link.Id });

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<QRCodeListResponse>();
        result!.QRCodes.Should().HaveCountGreaterThanOrEqualTo(1);
    }

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

        var link = await CreateLinkAsync(workspaceId, "qr-get-link");
        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/qrcodes", new { ShortLinkId = link.Id });
        var created = await createResponse.Content.ReadFromJsonAsync<QRCodeResponse>();

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

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

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

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

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

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

        var link = await CreateLinkAsync(workspaceId, "qr-update-link");
        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/qrcodes", new { ShortLinkId = link.Id });
        var created = await createResponse.Content.ReadFromJsonAsync<QRCodeResponse>();

        // Act
        var response = await _client.PutAsJsonAsync($"/workspaces/{workspaceId}/qrcodes/{created!.Id}", new
        {
            Style = new
            {
                ForegroundColor = "#0000FF",
                BackgroundColor = "#FFFF00"
            }
        });

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<QRCodeResponse>();
        result!.Style.ForegroundColor.Should().Be("#0000FF");
        result.Style.BackgroundColor.Should().Be("#FFFF00");
    }

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

        var link = await CreateLinkAsync(workspaceId, "qr-delete-link");
        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/qrcodes", new { ShortLinkId = link.Id });
        var created = await createResponse.Content.ReadFromJsonAsync<QRCodeResponse>();

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

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

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

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

        var link = await CreateLinkAsync(workspaceId, "qr-preview-link");
        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/qrcodes", new { ShortLinkId = link.Id });
        var created = await createResponse.Content.ReadFromJsonAsync<QRCodeResponse>();

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<QRCodePreviewResponse>();
        result!.DataUrl.Should().StartWith("data:image/png;base64,");
        result.Format.Should().Be("png");
    }

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

        var link = await CreateLinkAsync(workspaceId, "qr-export-png-link");
        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/qrcodes", new { ShortLinkId = link.Id });
        var created = await createResponse.Content.ReadFromJsonAsync<QRCodeResponse>();

        // Act
        var response = await _client.GetAsync($"/workspaces/{workspaceId}/qrcodes/{created!.Id}/export?format=png");

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        response.Content.Headers.ContentType!.MediaType.Should().Be("image/png");
    }

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

        var link = await CreateLinkAsync(workspaceId, "qr-export-svg-link");
        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId}/qrcodes", new { ShortLinkId = link.Id });
        var created = await createResponse.Content.ReadFromJsonAsync<QRCodeResponse>();

        // Act
        var response = await _client.GetAsync($"/workspaces/{workspaceId}/qrcodes/{created!.Id}/export?format=svg");

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        response.Content.Headers.ContentType!.MediaType.Should().Be("image/svg+xml");
    }

    [Fact]
    public async Task QRCode_CannotAccessOtherUsersQRCode()
    {
        // Arrange - Create two users
        var (token1, workspaceId1) = await SetupAuthAndWorkspaceAsync("qr-user1@example.com");
        var link = await CreateLinkAsync(workspaceId1, "qr-user1-link");
        var createResponse =
            await _client.PostAsJsonAsync($"/workspaces/{workspaceId1}/qrcodes", new { ShortLinkId = link.Id });
        var created = await createResponse.Content.ReadFromJsonAsync<QRCodeResponse>();

        var (token2, _) = await SetupAuthAndWorkspaceAsync("qr-user2@example.com");
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token2);

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

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