using System.Net;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Text.Json;
using DocumentOperator.API.Controllers;
using DocumentOperator.Domain.Models.ValueObjects;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;

namespace DocumentOperator.Tests.Integration.API;

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

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

    private static Stream LoadTestPdfAsStream(string fileName)
    {
        var assembly = Assembly.GetExecutingAssembly();
        var resourceName = $"DocumentOperator.Tests.TestData.Pdfs.{fileName}";
        return assembly.GetManifestResourceStream(resourceName) 
               ?? throw new FileNotFoundException($"Embedded resource not found: {resourceName}");
    }

    private static string LoadTestPdfAsBase64(string fileName)
    {
        using var stream = LoadTestPdfAsStream(fileName);
        using var ms = new MemoryStream();
        stream.CopyTo(ms);
        return Convert.ToBase64String(ms.ToArray());
    }

    #region Merge Endpoint Tests (existing - keeping for reference)

    [Fact]
    public async Task MergeFromFiles_ValidPdfs_ReturnsMergedPdf()
    {
        // Arrange
        using var content = new MultipartFormDataContent();
        
        using var pdf1Stream = LoadTestPdfAsStream("valid.pdf");
        using var pdf2Stream = LoadTestPdfAsStream("valid.pdf");
        
        var pdf1Content = new StreamContent(pdf1Stream);
        var pdf2Content = new StreamContent(pdf2Stream);
        
        pdf1Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        pdf2Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        
        content.Add(pdf1Content, "files", "file1.pdf");
        content.Add(pdf2Content, "files", "file2.pdf");

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        response.Content.Headers.ContentType?.MediaType.Should().Be("application/pdf");
        
        byte[] mergedPdf = await response.Content.ReadAsByteArrayAsync();
        mergedPdf.Should().NotBeEmpty();
        mergedPdf.Length.Should().BeGreaterThan(100); // Sanity check
    }

    [Fact]
    public async Task MergeFromBase64_ValidPdfs_ReturnsMergedPdf()
    {
        // Arrange
        string base64Pdf1 = LoadTestPdfAsBase64("valid.pdf");
        string base64Pdf2 = LoadTestPdfAsBase64("valid.pdf");

        var request = new MergePdfsBase64Request
        {
            Base64Pdfs = new List<string> { base64Pdf1, base64Pdf2 },
            PageRanges = null
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        byte[] mergedPdf = await response.Content.ReadAsByteArrayAsync();
        mergedPdf.Should().NotBeEmpty();
    }

    [Fact]
    public async Task MergeFromBase64_WithPageRanges_ReturnsMergedPdf()
    {
        // Arrange
        string base64Pdf1 = LoadTestPdfAsBase64("valid.pdf");
        string base64Pdf2 = LoadTestPdfAsBase64("valid.pdf");

        var request = new MergePdfsBase64Request
        {
            Base64Pdfs = new List<string> { base64Pdf1, base64Pdf2 },
            PageRanges = new List<string?> { "1", "1" } // Only first page from each
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        byte[] mergedPdf = await response.Content.ReadAsByteArrayAsync();
        mergedPdf.Should().NotBeEmpty();
    }

    [Fact]
    public async Task MergeFromFiles_OnePdf_Returns400()
    {
        // Arrange
        using var content = new MultipartFormDataContent();
        using var pdfStream = LoadTestPdfAsStream("valid.pdf");
        var pdfContent = new StreamContent(pdfStream);
        pdfContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        content.Add(pdfContent, "files", "file1.pdf");

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

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

    [Fact]
    public async Task MergeFromBase64_InvalidBase64_Returns400()
    {
        // Arrange
        var request = new MergePdfsBase64Request
        {
            Base64Pdfs = new List<string> { "INVALID_BASE64!!!", "ANOTHER_INVALID" }
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

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

    [Fact]
    public async Task MergeFromBase64_InvalidPageRange_Returns400()
    {
        // Arrange
        string base64Pdf = LoadTestPdfAsBase64("valid.pdf");

        var request = new MergePdfsBase64Request
        {
            Base64Pdfs = new List<string> { base64Pdf, base64Pdf },
            PageRanges = new List<string?> { "999-1000", null } // Exceeds page count
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

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

    [Fact]
    public async Task MergeFromFiles_CorruptedPdf_Returns500()
    {
        // Arrange
        using var content = new MultipartFormDataContent();
        
        byte[] corruptedData = "NOT A PDF FILE"u8.ToArray();
        var corruptedContent = new ByteArrayContent(corruptedData);
        corruptedContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        
        using var validPdfStream = LoadTestPdfAsStream("valid.pdf");
        var validContent = new StreamContent(validPdfStream);
        validContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        
        content.Add(corruptedContent, "files", "corrupted.pdf");
        content.Add(validContent, "files", "valid.pdf");

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

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

    #endregion

    #region Annotate Endpoint Tests

    [Fact]
    public async Task AnnotateFromFile_TextMarkupHighlight_ReturnsAnnotatedPdf()
    {
        // Arrange
        using var content = new MultipartFormDataContent();
        
        using var pdfStream = LoadTestPdfAsStream("valid.pdf");
        var pdfContent = new StreamContent(pdfStream);
        pdfContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        content.Add(pdfContent, "file", "test.pdf");
        
        content.Add(new StringContent(AnnotationType.TextMarkup.ToString()), "annotationType");
        content.Add(new StringContent("1"), "pageNumber");
        content.Add(new StringContent("100"), "x1");
        content.Add(new StringContent("100"), "y1");
        content.Add(new StringContent("200"), "x2");
        content.Add(new StringContent("120"), "y2");
        content.Add(new StringContent("Important text"), "content");
        content.Add(new StringContent("Test Author"), "author");
        content.Add(new StringContent("FFFF00"), "color");
        content.Add(new StringContent(TextMarkupStyle.Highlight.ToString()), "textMarkupStyle");

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        response.Content.Headers.ContentType?.MediaType.Should().Be("application/pdf");
        
        byte[] annotatedPdf = await response.Content.ReadAsByteArrayAsync();
        annotatedPdf.Should().NotBeEmpty();
        annotatedPdf.Length.Should().BeGreaterThan(100);
    }

    [Fact]
    public async Task AnnotateFromBase64_FreeText_ReturnsAnnotatedPdf()
    {
        // Arrange
        string base64Pdf = LoadTestPdfAsBase64("valid.pdf");

        var request = new AddAnnotationBase64Command
        {
            Base64Pdf = base64Pdf,
            AnnotationType = AnnotationType.FreeText,
            PageNumber = 1,
            X1 = 50,
            Y1 = 50,
            X2 = 150,
            Y2 = 100,
            Content = "Free text annotation",
            Author = "John Doe",
            Color = "FF0000"
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        byte[] annotatedPdf = await response.Content.ReadAsByteArrayAsync();
        annotatedPdf.Should().NotBeEmpty();
    }

    [Fact]
    public async Task AnnotateFromBase64_StickyNote_ReturnsAnnotatedPdf()
    {
        // Arrange
        string base64Pdf = LoadTestPdfAsBase64("valid.pdf");

        var request = new AddAnnotationBase64Command
        {
            Base64Pdf = base64Pdf,
            AnnotationType = AnnotationType.StickyNote,
            PageNumber = 1,
            X1 = 300,
            Y1 = 300,
            X2 = 320,
            Y2 = 320,
            Content = "Please review this section",
            Author = "Reviewer"
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        byte[] annotatedPdf = await response.Content.ReadAsByteArrayAsync();
        annotatedPdf.Should().NotBeEmpty();
    }

    [Fact]
    public async Task AnnotateFromFile_Circle_ReturnsAnnotatedPdf()
    {
        // Arrange
        using var content = new MultipartFormDataContent();
        
        using var pdfStream = LoadTestPdfAsStream("valid.pdf");
        var pdfContent = new StreamContent(pdfStream);
        pdfContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        content.Add(pdfContent, "file", "test.pdf");
        
        content.Add(new StringContent(AnnotationType.Circle.ToString()), "annotationType");
        content.Add(new StringContent("1"), "pageNumber");
        content.Add(new StringContent("100"), "x1");
        content.Add(new StringContent("200"), "y1");
        content.Add(new StringContent("200"), "x2");
        content.Add(new StringContent("300"), "y2");
        content.Add(new StringContent("Circle annotation"), "content");
        content.Add(new StringContent("00FF00"), "color");

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        byte[] annotatedPdf = await response.Content.ReadAsByteArrayAsync();
        annotatedPdf.Should().NotBeEmpty();
    }

    [Fact]
    public async Task AnnotateFromBase64_Square_ReturnsAnnotatedPdf()
    {
        // Arrange
        string base64Pdf = LoadTestPdfAsBase64("valid.pdf");

        var request = new AddAnnotationBase64Command
        {
            Base64Pdf = base64Pdf,
            AnnotationType = AnnotationType.Square,
            PageNumber = 1,
            X1 = 250,
            Y1 = 250,
            X2 = 350,
            Y2 = 350,
            Color = "0000FF"
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        byte[] annotatedPdf = await response.Content.ReadAsByteArrayAsync();
        annotatedPdf.Should().NotBeEmpty();
    }

    [Fact]
    public async Task AnnotateFromBase64_InvalidBase64_Returns400()
    {
        // Arrange
        var request = new AddAnnotationBase64Command
        {
            Base64Pdf = "INVALID_BASE64!!!",
            AnnotationType = AnnotationType.Circle,
            PageNumber = 1,
            X1 = 0,
            Y1 = 0,
            X2 = 100,
            Y2 = 100
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

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

    [Fact]
    public async Task AnnotateFromBase64_InvalidPageNumber_Returns400()
    {
        // Arrange
        string base64Pdf = LoadTestPdfAsBase64("valid.pdf");

        var request = new AddAnnotationBase64Command
        {
            Base64Pdf = base64Pdf,
            AnnotationType = AnnotationType.FreeText,
            PageNumber = 999, // Exceeds page count
            X1 = 0,
            Y1 = 0,
            X2 = 100,
            Y2 = 100,
            Content = "Test"
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

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

    [Fact]
    public async Task AnnotateFromBase64_FreeTextWithoutContent_Returns400()
    {
        // Arrange
        string base64Pdf = LoadTestPdfAsBase64("valid.pdf");

        var request = new AddAnnotationBase64Command
        {
            Base64Pdf = base64Pdf,
            AnnotationType = AnnotationType.FreeText,
            PageNumber = 1,
            X1 = 0,
            Y1 = 0,
            X2 = 100,
            Y2 = 100
            // Missing required Content
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

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

    [Fact]
    public async Task AnnotateFromBase64_TextMarkupWithoutStyle_Returns400()
    {
        // Arrange
        string base64Pdf = LoadTestPdfAsBase64("valid.pdf");

        var request = new AddAnnotationBase64Command
        {
            Base64Pdf = base64Pdf,
            AnnotationType = AnnotationType.TextMarkup,
            PageNumber = 1,
            X1 = 0,
            Y1 = 0,
            X2 = 100,
            Y2 = 100
            // Missing required TextMarkupStyle
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

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

    [Fact]
    public async Task AnnotateFromBase64_InvalidColorFormat_Returns400()
    {
        // Arrange
        string base64Pdf = LoadTestPdfAsBase64("valid.pdf");

        var request = new AddAnnotationBase64Command
        {
            Base64Pdf = base64Pdf,
            AnnotationType = AnnotationType.Circle,
            PageNumber = 1,
            X1 = 0,
            Y1 = 0,
            X2 = 100,
            Y2 = 100,
            Color = "INVALID" // Invalid hex format
        };

        var json = JsonSerializer.Serialize(request);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

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

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

    #endregion
}
