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

namespace TrackQrApi.Tests;

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

    private async Task<(string Token, Guid WorkspaceId)> GetAuthAndWorkspaceAsync(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 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;

        return (token, workspaceId);
    }

    private static MultipartFormDataContent CreateImageUpload(string filename, string contentType = "image/png")
    {
        var content = new MultipartFormDataContent();
        // Create a minimal valid PNG (1x1 transparent pixel)
        var pngBytes = new byte[]
        {
            0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, // PNG signature
            0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, // IHDR chunk
            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
            0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4,
            0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, 0x41,
            0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00,
            0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00,
            0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
            0x42, 0x60, 0x82 // IEND chunk
        };

        var fileContent = new ByteArrayContent(pngBytes);
        fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
        content.Add(fileContent, "file", filename);

        return content;
    }

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

        var content = CreateImageUpload("logo.png");

        // Act
        var response = await _client.PostAsync($"/workspaces/{workspaceId}/assets", content);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);
        var result = await response.Content.ReadFromJsonAsync<AssetResponse>();
        result.Should().NotBeNull();
        result!.Type.Should().Be("Logo");
        result.Mime.Should().Be("image/png");
        result.Size.Should().BeGreaterThan(0);
        result.Url.Should().NotBeNullOrEmpty();
    }

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

        var content = new MultipartFormDataContent();
        var fileContent = new ByteArrayContent(new byte[] { 0x00, 0x01, 0x02 });
        fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        content.Add(fileContent, "file", "document.pdf");

        // Act
        var response = await _client.PostAsync($"/workspaces/{workspaceId}/assets", content);

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

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

        var content = new MultipartFormDataContent();

        // Act
        var response = await _client.PostAsync($"/workspaces/{workspaceId}/assets", content);

        // Assert - either 400 or 500 is acceptable for empty multipart form
        response.IsSuccessStatusCode.Should().BeFalse();
    }

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

        var content = CreateImageUpload("list-test.png");
        await _client.PostAsync($"/workspaces/{workspaceId}/assets", content);

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

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

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

        var content = CreateImageUpload("get-test.png");
        var uploadResponse = await _client.PostAsync($"/workspaces/{workspaceId}/assets", content);
        var uploaded = await uploadResponse.Content.ReadFromJsonAsync<AssetResponse>();

        // Extract storage key from URL
        var storageKey = uploaded!.Url.Split('/').Last();

        // Act - Get asset publicly (no auth needed)
        _client.DefaultRequestHeaders.Authorization = null;
        var response = await _client.GetAsync($"/assets/{storageKey}");

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

    [Fact]
    public async Task GetAsset_WithInvalidStorageKey_ReturnsNotFound()
    {
        // Act
        var response = await _client.GetAsync($"/assets/{Guid.NewGuid()}.png");

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

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

        var content = CreateImageUpload("to-delete.png");
        var uploadResponse = await _client.PostAsync($"/workspaces/{workspaceId}/assets", content);
        var uploaded = await uploadResponse.Content.ReadFromJsonAsync<AssetResponse>();

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

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

        // Verify it's deleted from list
        var listResponse = await _client.GetAsync($"/workspaces/{workspaceId}/assets");
        var list = await listResponse.Content.ReadFromJsonAsync<AssetListResponse>();
        list!.Assets.Should().NotContain(a => a.Id == uploaded.Id);
    }

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

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

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

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

        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token1);
        var content = CreateImageUpload("user1-asset.png");
        var uploadResponse = await _client.PostAsync($"/workspaces/{workspaceId1}/assets", content);
        var uploaded = await uploadResponse.Content.ReadFromJsonAsync<AssetResponse>();

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

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

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

        var content = CreateImageUpload("public-test.png");
        var uploadResponse = await _client.PostAsync($"/workspaces/{workspaceId}/assets", content);
        var uploaded = await uploadResponse.Content.ReadFromJsonAsync<AssetResponse>();

        var storageKey = uploaded!.Url.Split('/').Last();

        // Act - Access without auth
        _client.DefaultRequestHeaders.Authorization = null;
        var response = await _client.GetAsync($"/assets/{storageKey}");

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        response.Headers.CacheControl!.MaxAge.Should().Be(TimeSpan.FromSeconds(31536000));
    }
}