using FluentAssertions;
using VectorSearchApp.Configuration;
using VectorSearchApp.Services;

namespace VectorSearchApp.Tests;

public class EmbeddingServiceIntegrationTests
{
    private readonly IEmbeddingService _embeddingService;
    private readonly int _expectedDimension = 384; // all-MiniLM-L6-v2 dimension

    public EmbeddingServiceIntegrationTests()
    {
        // Use the actual embedding service with local inference
        // Configure to use the ONNX model for local inference
        var config = new EmbeddingConfiguration
        {
            ModelName = "sentence-transformers/all-MiniLM-L6-v2",
            Dimension = _expectedDimension,
            UseLocalInference = true
        };
        
        _embeddingService = new EmbeddingService(config);
    }

    [Fact]
    public async Task GenerateEmbeddingAsync_WithValidInput_ShouldReturnEmbedding()
    {
        // Arrange
        var text = "123 Main Street, New York, NY 10001";

        // Act
        var result = await _embeddingService.GenerateEmbeddingAsync(text);

        // Assert
        result.Should().NotBeNull();
        result.Should().NotBeEmpty();
    }

    [Fact]
    public async Task GenerateEmbeddingAsync_WithValidInput_ShouldHaveCorrectDimension()
    {
        // Arrange
        var text = "123 Main Street, New York, NY 10001";

        // Act
        var result = await _embeddingService.GenerateEmbeddingAsync(text);

        // Assert
        result.Should().HaveCount(_expectedDimension);
    }

    [Fact]
    public async Task GenerateEmbeddingAsync_WithEmptyString_ShouldReturnEmbedding()
    {
        // Arrange
        var text = "";

        // Act
        var result = await _embeddingService.GenerateEmbeddingAsync(text);

        // Assert
        result.Should().NotBeNull();
        result.Should().HaveCount(_expectedDimension);
    }

    [Fact]
    public async Task GenerateEmbeddingAsync_WithShortText_ShouldReturnEmbedding()
    {
        // Arrange
        var text = "Hello";

        // Act
        var result = await _embeddingService.GenerateEmbeddingAsync(text);

        // Assert
        result.Should().NotBeNull();
        result.Should().HaveCount(_expectedDimension);
    }

    [Fact]
    public async Task GenerateEmbeddingAsync_WithLongText_ShouldReturnEmbedding()
    {
        // Arrange
        var text = "This is a much longer address that contains more text than typical short addresses. " +
                   "It includes multiple lines and details about the location. " +
                   "1234 Elm Street, Suite 500, Springfield, IL 62701, United States";

        // Act
        var result = await _embeddingService.GenerateEmbeddingAsync(text);

        // Assert
        result.Should().NotBeNull();
        result.Should().HaveCount(_expectedDimension);
    }

    [Fact]
    public async Task GenerateEmbeddingAsync_WithSimilarAddresses_ShouldReturnDifferentEmbeddings()
    {
        // Arrange
        var address1 = "123 Main Street, New York, NY 10001";
        var address2 = "124 Main Street, New York, NY 10001";

        // Act
        var embedding1 = await _embeddingService.GenerateEmbeddingAsync(address1);
        var embedding2 = await _embeddingService.GenerateEmbeddingAsync(address2);

        // Assert
        embedding1.Should().NotBeNull();
        embedding2.Should().NotBeNull();
        // Note: With mock local inference, embeddings may be similar but should not be identical
        embedding1.Should().NotBeEquivalentTo(embedding2);
    }

    [Fact]
    public async Task GenerateEmbeddingAsync_WithSameAddress_ShouldReturnSameEmbeddings()
    {
        // Arrange
        var text = "123 Main Street, New York, NY 10001";

        // Act
        var embedding1 = await _embeddingService.GenerateEmbeddingAsync(text);
        var embedding2 = await _embeddingService.GenerateEmbeddingAsync(text);

        // Assert
        embedding1.Should().NotBeNull();
        embedding2.Should().NotBeNull();
        embedding1.Should().BeEquivalentTo(embedding2);
    }

    [Fact]
    public async Task GenerateEmbeddingAsync_MultipleAddresses_ShouldReturnEmbeddings()
    {
        // Arrange
        var addresses = new[]
        {
            "123 Main Street, New York, NY 10001",
            "456 Oak Avenue, Los Angeles, CA 90001",
            "789 Pine Road, Chicago, IL 60601",
            "321 Maple Drive, Houston, TX 77001",
            "654 Cedar Lane, Phoenix, AZ 85001"
        };

        // Act & Assert
        foreach (var address in addresses)
        {
            var embedding = await _embeddingService.GenerateEmbeddingAsync(address);
            embedding.Should().NotBeNull();
            embedding.Should().HaveCount(_expectedDimension);
        }
    }

    [Fact]
    public async Task GenerateEmbeddingAsync_CancellationToken_ShouldWork()
    {
        // Arrange
        var text = "123 Main Street, New York, NY 10001";
        using var cts = new CancellationTokenSource();

        // Act
        var result = await _embeddingService.GenerateEmbeddingAsync(text, cts.Token);

        // Assert
        result.Should().NotBeNull();
        result.Should().HaveCount(_expectedDimension);
    }
}
