using DocumentOperator.API.Controllers; // For Base64Request DTOs
using DocumentOperator.Application.Common.DTOs;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using System.Net;
using System.Net.Http.Json;
using Xunit;

namespace DocumentOperator.Tests.Integration.API;

public class PdfValidationControllerTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly WebApplicationFactory<Program> _factory;
    private readonly HttpClient _client;

    public PdfValidationControllerTests(WebApplicationFactory<Program> factory)
    {
        _factory = factory;
        _client = _factory.CreateClient();
    }

    #region Base64 JSON Tests

    [Fact]
    public async Task POST_ValidatePdf_Base64_ValidPdf_Returns200()
    {
        // Arrange
        // Verwende ein echtes Test-PDF (embedded resource aus Unit Tests)
        var assembly = typeof(PdfValidationControllerTests).Assembly;
        var resourceName = "DocumentOperator.Tests.TestData.Pdfs.valid.pdf";

        byte[] pdfBytes;
        using (var stream = assembly.GetManifestResourceStream(resourceName))
        {
            if (stream == null)
            {
                throw new InvalidOperationException($"Test resource '{resourceName}' not found");
            }

            using var ms = new MemoryStream();
            await stream.CopyToAsync(ms);
            pdfBytes = ms.ToArray();
        }

        var base64Pdf = Convert.ToBase64String(pdfBytes);
        var request = new ValidatePdfBase64Request { Base64Pdf = base64Pdf };

        // Act
        var response = await _client.PostAsJsonAsync("/api/pdf/validation/validate", request);

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

        var result = await response.Content.ReadFromJsonAsync<PdfValidationResult>();
        result.Should().NotBeNull();
        result!.PageCount.Should().BeGreaterThan(0);
        result.FileSizeBytes.Should().BeGreaterThan(0);
        result.PdfVersion.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public async Task POST_ValidatePdf_Base64_InvalidBase64_Returns400()
    {
        // Arrange
        var request = new ValidatePdfBase64Request { Base64Pdf = "invalid-base64!!!" }; // Kein gültiges Base64

        // Act
        var response = await _client.PostAsJsonAsync("/api/pdf/validation/validate", request);

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

        var problemDetails = await response.Content.ReadAsStringAsync();
        // FormatException message contains "Base-64" (with hyphen)
        problemDetails.Should().MatchRegex("(?i)base.?64", "should contain Base64 validation error");
    }

    [Fact]
    public async Task POST_ValidatePdf_Base64_EmptyPdf_Returns400()
    {
        // Arrange
        var request = new ValidatePdfBase64Request { Base64Pdf = string.Empty }; // Leerer String

        // Act
        var response = await _client.PostAsJsonAsync("/api/pdf/validation/validate", request);

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

        var problemDetails = await response.Content.ReadAsStringAsync();
        // Empty Base64 causes FormatException or empty stream error
        problemDetails.Should().MatchRegex("(Base64|empty|stream)", "should contain validation error message");
    }

    #endregion

    #region Multipart/Form-Data Tests

    [Fact]
    public async Task POST_ValidatePdf_Multipart_ValidPdf_Returns200()
    {
        // Arrange
        var assembly = typeof(PdfValidationControllerTests).Assembly;
        var resourceName = "DocumentOperator.Tests.TestData.Pdfs.valid.pdf";

        byte[] pdfBytes;
        using (var stream = assembly.GetManifestResourceStream(resourceName))
        {
            if (stream == null)
            {
                throw new InvalidOperationException($"Test resource '{resourceName}' not found");
            }

            using var ms = new MemoryStream();
            await stream.CopyToAsync(ms);
            pdfBytes = ms.ToArray();
        }

        // Create multipart/form-data content
        using var content = new MultipartFormDataContent();
        var fileContent = new ByteArrayContent(pdfBytes);
        fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
        content.Add(fileContent, "file", "test.pdf");

        // Act
        var response = await _client.PostAsync("/api/pdf/validation/validate", content);

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

        var result = await response.Content.ReadFromJsonAsync<PdfValidationResult>();
        result.Should().NotBeNull();
        result!.PageCount.Should().BeGreaterThan(0);
        result.FileSizeBytes.Should().BeGreaterThan(0);
        result.PdfVersion.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public async Task POST_ValidatePdf_Multipart_EmptyFile_Returns400()
    {
        // Arrange
        using var content = new MultipartFormDataContent();
        var fileContent = new ByteArrayContent(Array.Empty<byte>());
        fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
        content.Add(fileContent, "file", "empty.pdf");

        // Act
        var response = await _client.PostAsync("/api/pdf/validation/validate", content);

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

        var problemDetails = await response.Content.ReadAsStringAsync();
        problemDetails.Should().Contain("cannot be empty");
    }

    [Fact]
    public async Task POST_ValidatePdf_Multipart_NoFile_Returns400()
    {
        // Arrange
        using var content = new MultipartFormDataContent();

        // Act
        var response = await _client.PostAsync("/api/pdf/validation/validate", content);

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

    #endregion

    #region PDF/A Validation Tests (Base64)

    [Fact]
    public async Task POST_ValidatePdfA_Base64_ValidPdf_Returns200()
    {
        // Arrange
        var assembly = typeof(PdfValidationControllerTests).Assembly;
        var resourceName = "DocumentOperator.Tests.TestData.Pdfs.valid.pdf";

        byte[] pdfBytes;
        using (var stream = assembly.GetManifestResourceStream(resourceName))
        {
            if (stream == null)
            {
                throw new InvalidOperationException($"Test resource '{resourceName}' not found");
            }

            using var ms = new MemoryStream();
            await stream.CopyToAsync(ms);
            pdfBytes = ms.ToArray();
        }

        var base64Pdf = Convert.ToBase64String(pdfBytes);
        var request = new ValidatePdfABase64Request { Base64Pdf = base64Pdf };

        // Act
        var response = await _client.PostAsJsonAsync("/api/pdf/validation/validate-pdfa", request);

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

        var result = await response.Content.ReadFromJsonAsync<PdfAValidationResult>();
        result.Should().NotBeNull();
        result!.IsValid.Should().BeTrue();
        result.PageCount.Should().BeGreaterThan(0);
        result.PdfVersion.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public async Task POST_ValidatePdfA_Base64_InvalidBase64_Returns400()
    {
        // Arrange
        var request = new ValidatePdfABase64Request { Base64Pdf = "invalid-base64!!!" };

        // Act
        var response = await _client.PostAsJsonAsync("/api/pdf/validation/validate-pdfa", request);

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

        var problemDetails = await response.Content.ReadAsStringAsync();
        // FormatException message contains "Base-64" (with hyphen)
        problemDetails.Should().MatchRegex("(?i)base.?64", "should contain Base64 validation error");
    }

    [Fact]
    public async Task POST_ValidatePdfA_Base64_EmptyPdf_Returns400()
    {
        // Arrange
        var request = new ValidatePdfABase64Request { Base64Pdf = string.Empty };

        // Act
        var response = await _client.PostAsJsonAsync("/api/pdf/validation/validate-pdfa", request);

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

        var problemDetails = await response.Content.ReadAsStringAsync();
        // Empty Base64 causes FormatException or empty stream error
        problemDetails.Should().MatchRegex("(Base64|empty|stream)", "should contain validation error message");
    }

    #endregion

    #region PDF/A Validation Tests (Multipart)

    [Fact]
    public async Task POST_ValidatePdfA_Multipart_ValidPdf_Returns200()
    {
        // Arrange
        var assembly = typeof(PdfValidationControllerTests).Assembly;
        var resourceName = "DocumentOperator.Tests.TestData.Pdfs.valid.pdf";

        byte[] pdfBytes;
        using (var stream = assembly.GetManifestResourceStream(resourceName))
        {
            if (stream == null)
            {
                throw new InvalidOperationException($"Test resource '{resourceName}' not found");
            }

            using var ms = new MemoryStream();
            await stream.CopyToAsync(ms);
            pdfBytes = ms.ToArray();
        }

        // Create multipart/form-data content
        using var content = new MultipartFormDataContent();
        var fileContent = new ByteArrayContent(pdfBytes);
        fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
        content.Add(fileContent, "file", "test.pdf");

        // Act
        var response = await _client.PostAsync("/api/pdf/validation/validate-pdfa", content);

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

        var result = await response.Content.ReadFromJsonAsync<PdfAValidationResult>();
        result.Should().NotBeNull();
        result!.IsValid.Should().BeTrue();
        result.PageCount.Should().BeGreaterThan(0);
        result.PdfVersion.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public async Task POST_ValidatePdfA_Multipart_EmptyFile_Returns400()
    {
        // Arrange
        using var content = new MultipartFormDataContent();
        var fileContent = new ByteArrayContent(Array.Empty<byte>());
        fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
        content.Add(fileContent, "file", "empty.pdf");

        // Act
        var response = await _client.PostAsync("/api/pdf/validation/validate-pdfa", content);

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

        var problemDetails = await response.Content.ReadAsStringAsync();
        problemDetails.Should().Contain("cannot be empty");
    }

    [Fact]
    public async Task POST_ValidatePdfA_Multipart_NoFile_Returns400()
    {
        // Arrange
        using var content = new MultipartFormDataContent();

        // Act
        var response = await _client.PostAsync("/api/pdf/validation/validate-pdfa", content);

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

    #endregion
}
