content: /**
   * Copyright (C) 2024 AIDC-AI
   * <p>
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * <p>
   * http://www.apache.org/licenses/LICENSE-2.0
   * <p>
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package com.alibaba.langengine.qdrant.vectorstore;
  
  import com.alibaba.langengine.core.indexes.Document;
  import com.alibaba.langengine.core.embeddings.Embeddings;
  import org.junit.jupiter.api.Test;
  import org.junit.jupiter.api.BeforeEach;
  import org.junit.jupiter.api.DisplayName;
  import org.junit.jupiter.api.Nested;
  import org.mockito.Mock;
  import org.mockito.MockitoAnnotations;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.UUID;
  
  import static org.junit.jupiter.api.Assertions.*;
  
  /**
   * Qdrant vector store test
   *
   * @author zh_xiaoji
   */
  public class QdrantTest {
  
      private static final String QDRANT_HOST = "localhost";
      private static final int QDRANT_PORT = 6333;
      private static final String TEST_COLLECTION = "test_collection";
  
      @Test
      public void test_qdrant_service_connection() {
          System.out.println("=== Testing Qdrant Service Connection ===");
  
          // Create QdrantService instance
          QdrantService qdrantService = new QdrantService("http://" + QDRANT_HOST + ":" + QDRANT_PORT);
  
          // 测试连接
          boolean isConnected = qdrantService.isHealthy();
          System.out.println("Connection test result: " + (isConnected ? "SUCCESS" : "FAILED"));
  
          if (isConnected) {
              // 测试集合操作
              try {
                  boolean exists = qdrantService.collectionExists("test_collection");
                  System.out.println("Collection exists: " + exists);
              } catch (Exception e) {
                  System.out.println("Collection check failed (expected if collection doesn't exist): " + e.getMessage());
              }
  
              // 获取集群信息
              try {
                  String clusterInfo = qdrantService.getClusterInfo();
                  System.out.println("Cluster info: " + clusterInfo);
              } catch (Exception e) {
                  System.out.println("Cluster info failed: " + e.getMessage());
              }
  
              // 获取集合列表
              try {
                  String collections = qdrantService.listCollections();
                  System.out.println("Collections: " + collections);
              } catch (Exception e) {
                  System.out.println("List collections failed: " + e.getMessage());
              }
          } else {
              System.out.println("Please ensure Qdrant service is running at " + QDRANT_HOST + ":" + QDRANT_PORT);
              System.out.println("Start command: docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant");
          }
  
          // Note: In actual CI/CD environment, this test will fail if Qdrant service is unavailable
          // In development environment, we can skip assertions and just print results
          // assertTrue("Qdrant service should be accessible", isConnected);
      }
  
      @Test
      public void test_qdrant_vector_store_creation() {
          System.out.println("=== Testing Qdrant Vector Store Creation ===");
  
          // Create Qdrant instance (basic functionality test)
          Qdrant qdrant = new Qdrant(TEST_COLLECTION);
  
          assertNotNull(qdrant, "Qdrant instance should not be null");
          assertEquals(TEST_COLLECTION, qdrant.getCollectionName(), "Collection name should match");
  
          System.out.println("Qdrant vector store created successfully");
          System.out.println("Host: localhost");
          System.out.println("Port: 6333");
          System.out.println("Collection: " + qdrant.getCollectionName());
      }
  
      @Test
      public void test_qdrant_with_api_key() {
          System.out.println("=== Testing Qdrant with API Key ===");
  
          Qdrant qdrant = new Qdrant(TEST_COLLECTION);
  
          assertNotNull(qdrant, "Qdrant instance should not be null");
  
          System.out.println("Qdrant with API key created successfully");
      }
  
      @Test
      public void test_qdrant_add_documents() {
          System.out.println("=== Testing Qdrant Add Documents ===");
  
          // Create Qdrant instance
          Qdrant qdrant = new Qdrant(TEST_COLLECTION);
  
          // Create test documents (without embedding)
          List<Document> documents = new ArrayList<>();
          Document doc1 = new Document();
          doc1.setUniqueId(UUID.randomUUID().toString());
          doc1.setPageContent("This is a test document");
          doc1.setMetadata(Map.of("source", "test", "type", "example"));
          documents.add(doc1);
  
          try {
              // Try to add documents (expected to fail without embedding)
              qdrant.addDocuments(documents);
              System.out.println("Documents added successfully (unexpected)");
          } catch (Exception e) {
              System.out.println("Expected behavior when no embedding is provided: " + e.getClass().getSimpleName() + ": " + e.getMessage());
          }
      }
  
      @Test
      public void test_qdrant_similarity_search() {
          System.out.println("=== Testing Qdrant Similarity Search ===");
  
          // Create Qdrant instance
          Qdrant qdrant = new Qdrant(TEST_COLLECTION);
  
          // Execute similarity search (without embedding model)
          try {
              List<Document> results = qdrant.similaritySearch("test query", 5, null, null);
              System.out.println("similaritySearch method executed successfully, returned " + results.size() + " results");
          } catch (Exception e) {
              System.out.println("similaritySearch failed as expected: " + e.getMessage());
          }
      }
  
  
      @Nested
      @DisplayName("QdrantService Core Functions Tests")
      class QdrantServiceTests {
  
          private QdrantService qdrantService;
          private List<Document> testDocuments;
  
          @BeforeEach
          void setUp() {
              qdrantService = new QdrantService("http://" + QDRANT_HOST + ":" + QDRANT_PORT);
              testDocuments = createTestDocuments();
          }
  
          @Test
          @DisplayName("Test isHealthy() method")
          void testIsHealthy() {
              System.out.println("Testing isHealthy() method...");
  
              // Test health check
              boolean result = qdrantService.isHealthy();
              System.out.println("Health check result: " + result);
  
              // In CI environment, this might fail, so we just log the result
              // assertTrue(result, "Qdrant service should be healthy");
          }
  
          @Test
          @DisplayName("Test collection management functions")
          void testCollectionManagement() {
              System.out.println("Testing collection management functions...");
  
              try {
                  // Test listCollections
                  String collections = qdrantService.listCollections();
                  assertNotNull(collections, "Collections list should not be null");
                  System.out.println("Collections: " + collections);
  
                  // Test collectionExists
                  boolean exists = qdrantService.collectionExists(TEST_COLLECTION);
                  System.out.println("Collection '" + TEST_COLLECTION + "' exists: " + exists);
  
                  // Test getClusterInfo
                  String clusterInfo = qdrantService.getClusterInfo();
                  assertNotNull(clusterInfo, "Cluster info should not be null");
                  System.out.println("Cluster info: " + clusterInfo);
  
              } catch (Exception e) {
                  System.out.println("Collection management test failed (expected if service unavailable): " + e.getMessage());
              }
          }
  
          @Test
          @DisplayName("Test addPoints() method with stream optimization")
          void testAddPoints() {
              System.out.println("Testing addPoints() method with stream optimization...");
  
              try {
                  // Test with valid documents
                  boolean result = qdrantService.addPoints(TEST_COLLECTION, testDocuments);
                  System.out.println("Add points result: " + result);
  
                  // Test with empty list
                  boolean emptyResult = qdrantService.addPoints(TEST_COLLECTION, new ArrayList<>());
                  System.out.println("Add empty points result: " + emptyResult);
  
              } catch (Exception e) {
                  System.out.println("Add points test failed (expected if service unavailable): " + e.getMessage());
              }
          }
  
          @Test
          @DisplayName("Test searchSimilar() method with stream optimization")
          void testSearchSimilar() {
              System.out.println("Testing searchSimilar() method with stream optimization...");
  
              try {
                  // Create test query vector
                  List<Float> queryVector = Arrays.asList(0.1f, 0.2f, 0.3f, 0.4f, 0.5f);
  
                  // Test similarity search
                  List<Document> results = qdrantService.searchSimilar(TEST_COLLECTION, queryVector, 5, null);
                  assertNotNull(results, "Search results should not be null");
                  System.out.println("Search returned " + results.size() + " results");
  
                  // Verify result structure
                  for (Document doc : results) {
                      assertNotNull(doc.getUniqueId(), "Document ID should not be null");
                      System.out.println("Result doc ID: " + doc.getUniqueId() + ", Score: " + doc.getScore());
                  }
  
              } catch (Exception e) {
                  System.out.println("Search similar test failed (expected if service unavailable): " + e.getMessage());
              }
          }
  
          @Test
          @DisplayName("Test countPoints() method")
          void testCountPoints() {
              System.out.println("Testing countPoints() method...");
  
              try {
                  long count = qdrantService.countPoints(TEST_COLLECTION);
                  assertTrue(count >= 0, "Point count should be non-negative");
                  System.out.println("Collection '" + TEST_COLLECTION + "' has " + count + " points");
  
              } catch (Exception e) {
                  System.out.println("Count points test failed (expected if service unavailable): " + e.getMessage());
              }
          }
  
          @Test
          @DisplayName("Test API key validation")
          void testApiKeyValidation() {
              System.out.println("Testing API key validation...");
  
              // Test null API key
              assertThrows(IllegalArgumentException.class, () -> {
                  new QdrantService("http://localhost:6333", null);
              }, "Should throw exception for null API key");
  
              // Test empty API key
              assertThrows(IllegalArgumentException.class, () -> {
                  new QdrantService("http://localhost:6333", "");
              }, "Should throw exception for empty API key");
  
              // Test valid API key
              assertDoesNotThrow(() -> {
                  new QdrantService("http://localhost:6333", "valid-api-key");
              }, "Should not throw exception for valid API key");
  
              System.out.println("API key validation tests passed");
          }
      }
  
      @Nested
      @DisplayName("Qdrant Vector Store Tests")
      class QdrantVectorStoreTests {
  
          private Qdrant qdrant;
          @Mock
          private Embeddings mockEmbeddings;
  
          @BeforeEach
          void setUp() {
              MockitoAnnotations.initMocks(this);
              qdrant = new Qdrant(TEST_COLLECTION);
          }
  
          @Test
          @DisplayName("Test Qdrant constructor and getters")
          void testConstructorAndGetters() {
              System.out.println("Testing Qdrant constructor and getters...");
  
              // Test basic constructor
              Qdrant basicQdrant = new Qdrant(TEST_COLLECTION);
              assertNotNull(basicQdrant, "Qdrant instance should not be null");
              assertEquals(TEST_COLLECTION, basicQdrant.getCollectionName(), "Collection name should match");
  
              // Test constructor with embeddings (set via setter)
              Qdrant qdrantWithEmbeddings = new Qdrant(TEST_COLLECTION);
              qdrantWithEmbeddings.setEmbedding(mockEmbeddings);
              assertNotNull(qdrantWithEmbeddings, "Qdrant with embeddings should not be null");
              assertEquals(TEST_COLLECTION, qdrantWithEmbeddings.getCollectionName(), "Collection name should match");
              assertNotNull(qdrantWithEmbeddings.getEmbedding(), "Embedding should be set");
  
              System.out.println("Constructor and getter tests passed");
          }
  
          @Test
          @DisplayName("Test addDocuments() method with stream optimization")
          void testAddDocuments() {
              System.out.println("Testing addDocuments() method with stream optimization...");
  
              List<Document> documents = createTestDocuments();
  
              try {
                  // Test adding documents (will fail without embeddings)
                  qdrant.addDocuments(documents);
                  System.out.println("Documents added successfully (unexpected without embeddings)");
              } catch (Exception e) {
                  System.out.println("Expected failure when adding documents without embeddings: " + e.getClass().getSimpleName());
                  assertTrue(e.getMessage().contains("embedding") || e.getMessage().contains("vector") || e.getMessage().contains("connection"),
                          "Error should be related to embeddings or connection");
              }
          }
  
          @Test
          @DisplayName("Test addTexts() method with stream optimization")
          void testAddTexts() {
              System.out.println("Testing addTexts() method with stream optimization...");
  
              List<String> texts = Arrays.asList(
                      "This is the first test document",
                      "This is the second test document",
                      "This is the third test document"
              );
  
              List<Map<String, Object>> metadata = Arrays.asList(
                      Map.of("source", "test1", "type", "example"),
                      Map.of("source", "test2", "type", "example"),
                      Map.of("source", "test3", "type", "example")
              );
  
              try {
                  // Test adding texts (will fail without embeddings) - passing null for ids to auto-generate
                  List<String> ids = qdrant.addTexts(texts, metadata, null);
                  assertNotNull(ids, "Returned IDs should not be null");
                  assertEquals(texts.size(), ids.size(), "Should return same number of IDs as texts");
                  System.out.println("Texts added successfully, returned " + ids.size() + " IDs");
              } catch (Exception e) {
                  System.out.println("Expected failure when adding texts without embeddings: " + e.getClass().getSimpleName());
              }
          }
  
          @Test
          @DisplayName("Test similaritySearch() methods")
          void testSimilaritySearch() {
              System.out.println("Testing similaritySearch() methods...");
  
              String query = "test query";
  
              try {
                  // Test basic similarity search
                  List<Document> results1 = qdrant.similaritySearch(query, 5);
                  assertNotNull(results1, "Search results should not be null");
                  System.out.println("Basic similarity search returned " + results1.size() + " results");
  
                  // Test similarity search with distance threshold
                  List<Document> results2 = qdrant.similaritySearch(query, 5, 0.8, null);
                  assertNotNull(results2, "Distance-filtered search results should not be null");
                  System.out.println("Distance-filtered similarity search returned " + results2.size() + " results");
  
              } catch (Exception e) {
                  System.out.println("Similarity search failed (expected without embeddings): " + e.getMessage());
              }
          }
  
          @Test
          @DisplayName("Test additional Qdrant utility methods")
          void testUtilityMethods() {
              System.out.println("Testing Qdrant utility methods...");
  
              try {
                  // Test collection existence check
                  boolean exists = qdrant.collectionExists();
                  System.out.println("Collection exists: " + exists);
  
                  // Test point counting
                  long count = qdrant.countPoints();
                  assertTrue(count >= 0, "Point count should be non-negative");
                  System.out.println("Point count: " + count);
  
                  // Test collection info
                  Map<String, Object> info = qdrant.getCollectionInfo();
                  assertNotNull(info, "Collection info should not be null");
                  System.out.println("Collection info retrieved successfully");
  
              } catch (Exception e) {
                  System.out.println("Utility methods test failed (expected if service unavailable): " + e.getMessage());
              }
          }
      }
  
      @Nested
      @DisplayName("Helper Method Tests")
      class HelperMethodTests {
  
          @Test
          @DisplayName("Test document creation and validation")
          void testDocumentCreation() {
              System.out.println("Testing document creation and validation...");
  
              List<Document> documents = createTestDocuments();
  
              assertNotNull(documents, "Documents list should not be null");
              assertFalse(documents.isEmpty(), "Documents list should not be empty");
  
              for (Document doc : documents) {
                  assertNotNull(doc.getUniqueId(), "Document ID should not be null");
                  assertNotNull(doc.getPageContent(), "Document content should not be null");
                  assertFalse(doc.getPageContent().trim().isEmpty(), "Document content should not be empty");
  
                  if (doc.getMetadata() != null) {
                      assertFalse(doc.getMetadata().isEmpty(), "Document metadata should not be empty if present");
                  }
  
                  System.out.println("Document validated: ID=" + doc.getUniqueId() + ", Content length=" + doc.getPageContent().length());
              }
          }
  
          @Test
          @DisplayName("Test edge cases and error handling")
          void testEdgeCases() {
              System.out.println("Testing edge cases and error handling...");
  
              Qdrant qdrant = new Qdrant(TEST_COLLECTION);
  
              // Test with null documents (should handle gracefully, not throw exception)
              assertDoesNotThrow(() -> {
                  qdrant.addDocuments(null);
              }, "Should handle null documents gracefully");
              
              // Test with empty documents list
              assertDoesNotThrow(() -> {
                  qdrant.addDocuments(new ArrayList<>());
              }, "Should handle empty documents list gracefully");
              
              // Test with null texts (should throw NullPointerException as expected)
              assertThrows(NullPointerException.class, () -> {
                  qdrant.addTexts(null, null, null);
              }, "Should throw NullPointerException for null texts");
  
              // Test with empty texts list
              assertDoesNotThrow(() -> {
                  qdrant.addTexts(new ArrayList<>(), null, null);
              }, "Should handle empty texts list gracefully");
              System.out.println("Edge case tests completed");
          }
      }
  
      // ========== HELPER METHODS ==========
  
      /**
       * Create test documents with embeddings for testing
       */
      private List<Document> createTestDocuments() {
          List<Document> documents = new ArrayList<>();
  
          // Document 1
          Document doc1 = new Document();
          doc1.setUniqueId(UUID.randomUUID().toString());
          doc1.setPageContent("This is the first test document for Qdrant vector store testing");
          doc1.setEmbedding(Arrays.asList(0.1, 0.2, 0.3, 0.4, 0.5));
          Map<String, Object> metadata1 = new HashMap<>();
          metadata1.put("source", "test1");
          metadata1.put("type", "example");
          metadata1.put("category", "testing");
          doc1.setMetadata(metadata1);
          documents.add(doc1);
  
          // Document 2
          Document doc2 = new Document();
          doc2.setUniqueId(UUID.randomUUID().toString());
          doc2.setPageContent("This is the second test document with different content for similarity testing");
          doc2.setEmbedding(Arrays.asList(0.2, 0.3, 0.4, 0.5, 0.6));
          Map<String, Object> metadata2 = new HashMap<>();
          metadata2.put("source", "test2");
          metadata2.put("type", "example");
          metadata2.put("category", "validation");
          doc2.setMetadata(metadata2);
          documents.add(doc2);
  
          // Document 3
          Document doc3 = new Document();
          doc3.setUniqueId(UUID.randomUUID().toString());
          doc3.setPageContent("This is the third test document to verify stream-based processing works correctly");
          doc3.setEmbedding(Arrays.asList(0.3, 0.4, 0.5, 0.6, 0.7));
          Map<String, Object> metadata3 = new HashMap<>();
          metadata3.put("source", "test3");
          metadata3.put("type", "example");
          metadata3.put("category", "optimization");
          doc3.setMetadata(metadata3);
          documents.add(doc3);
  
          return documents;
      }
  
      /**
       * 手动测试方法 - 可以单独运行来测试Qdrant连接
       */
      public static void main(String[] args) {
          System.out.println("=== Manual Qdrant Connection Test ===");
  
          QdrantTest test = new QdrantTest();
          test.test_qdrant_service_connection();
          test.test_qdrant_vector_store_creation();
  
          System.out.println("\n=== Test completed ===");
          System.out.println("如果连接失败，请确保:");
          System.out.println("1. Docker已安装并运行");
          System.out.println("2. 运行命令: docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant");
          System.out.println("3. 或使用docker-compose: docker-compose -f docker-compose-qdrant.yml up -d");
          System.out.println("4. 访问 http://localhost:6333/dashboard 查看Qdrant Web UI");
      }
  }
  