#!/usr/bin/env node

/**
 * Embeddings-Based Conversation Memory Test Suite
 *
 * Tests the vector embeddings functionality for semantic search
 */

const axios = require('axios');

const BASE_URL = 'http://localhost:3020/api/v1/ai';
const colors = {
  reset: '\x1b[0m',
  green: '\x1b[32m',
  red: '\x1b[31m',
  yellow: '\x1b[33m',
  blue: '\x1b[34m',
  cyan: '\x1b[36m',
};

function log(color, message) {
  console.log(`${colors[color]}${message}${colors.reset}`);
}

function logTest(testName) {
  console.log(`\n${colors.cyan}━━━ ${testName} ━━━${colors.reset}`);
}

function logSuccess(message) {
  log('green', `✓ ${message}`);
}

function logError(message) {
  log('red', `✗ ${message}`);
}

function logInfo(message) {
  log('blue', `ℹ ${message}`);
}

async function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// Test 1: Health Check
async function testHealthCheck() {
  logTest('Test 1: Embeddings Service Health Check');
  try {
    const response = await axios.get(`${BASE_URL}/test/embeddings/health`);

    if (response.data.success && response.data.data.status === 'ok') {
      logSuccess(`Health check passed: ${response.data.data.message}`);
      return true;
    } else {
      logError(`Health check failed: ${response.data.data.message}`);
      return false;
    }
  } catch (error) {
    logError(`Health check error: ${error.message}`);
    if (error.response?.data) {
      console.log(JSON.stringify(error.response.data, null, 2));
    }
    return false;
  }
}

// Test 2: Generate Embedding
async function testGenerateEmbedding() {
  logTest('Test 2: Generate Vector Embedding');
  try {
    const testText = "My baby had a feeding session with 4 oz of formula";
    logInfo(`Generating embedding for: "${testText}"`);

    const response = await axios.post(`${BASE_URL}/test/embeddings/generate`, {
      text: testText
    });

    if (response.data.success) {
      const { dimensions, tokenCount, model, preview } = response.data.data;
      logSuccess(`Embedding generated successfully`);
      logInfo(`  Model: ${model}`);
      logInfo(`  Dimensions: ${dimensions}`);
      logInfo(`  Token count: ${tokenCount}`);
      logInfo(`  Preview (first 5): [${preview.join(', ')}...]`);
      return true;
    } else {
      logError('Embedding generation failed');
      return false;
    }
  } catch (error) {
    logError(`Embedding generation error: ${error.message}`);
    if (error.response?.data) {
      console.log(JSON.stringify(error.response.data, null, 2));
    }
    return false;
  }
}

// Test 3: Create Conversation with Embeddings
async function testCreateConversationWithEmbeddings() {
  logTest('Test 3: Create Conversation and Store Embeddings');
  try {
    const conversations = [
      { message: "My baby slept for 3 hours during the night", topic: "sleep" },
      { message: "She had a feeding session with 5 oz of formula", topic: "feeding" },
      { message: "Changed a wet diaper at 3pm", topic: "diaper" },
      { message: "Baby has a slight fever, should I be worried?", topic: "health" },
      { message: "She started crawling today! So excited!", topic: "development" },
    ];

    const conversationIds = [];

    for (const conv of conversations) {
      logInfo(`Creating conversation: "${conv.message}" (${conv.topic})`);

      const response = await axios.post(`${BASE_URL}/chat`, {
        message: conv.message
      });

      if (response.data.success) {
        const conversationId = response.data.data.conversationId;
        conversationIds.push({ id: conversationId, topic: conv.topic, message: conv.message });
        logSuccess(`  Created conversation ${conversationId}`);
        logInfo(`  AI Response: ${response.data.data.message.substring(0, 100)}...`);
      } else {
        logError(`  Failed to create conversation`);
      }

      // Wait to allow embeddings to be stored
      await sleep(1000);
    }

    logSuccess(`Created ${conversationIds.length} conversations with embeddings`);
    return conversationIds;
  } catch (error) {
    logError(`Conversation creation error: ${error.message}`);
    if (error.response?.data) {
      console.log(JSON.stringify(error.response.data, null, 2));
    }
    return [];
  }
}

// Test 4: Semantic Search
async function testSemanticSearch(conversationIds) {
  logTest('Test 4: Semantic Search for Similar Conversations');

  const searchQueries = [
    { query: "How long should my baby sleep at night?", expectedTopic: "sleep" },
    { query: "What's the right amount of milk for feeding?", expectedTopic: "feeding" },
    { query: "When should I change diapers?", expectedTopic: "diaper" },
    { query: "Is a high temperature dangerous?", expectedTopic: "health" },
    { query: "What are the milestones for a 6 month old?", expectedTopic: "development" },
  ];

  let successCount = 0;

  for (const searchQuery of searchQueries) {
    logInfo(`\nSearching: "${searchQuery.query}"`);

    try {
      const response = await axios.post(`${BASE_URL}/test/embeddings/search`, {
        query: searchQuery.query,
        userId: 'test_user_123',
        threshold: 0.5,
        limit: 3
      });

      if (response.data.success && response.data.data.results.length > 0) {
        const results = response.data.data.results;
        logSuccess(`  Found ${results.length} similar conversation(s)`);

        results.forEach((result, index) => {
          const similarity = (result.similarity * 100).toFixed(1);
          logInfo(`  ${index + 1}. Similarity: ${similarity}%`);
          logInfo(`     Topics: [${result.topics.join(', ')}]`);
          logInfo(`     Content: "${result.messageContent.substring(0, 60)}..."`);

          // Check if expected topic is in results
          if (result.topics.includes(searchQuery.expectedTopic)) {
            logSuccess(`     ✓ Found expected topic: ${searchQuery.expectedTopic}`);
          }
        });

        successCount++;
      } else {
        logError(`  No similar conversations found`);
      }
    } catch (error) {
      logError(`  Search error: ${error.message}`);
      if (error.response?.data) {
        console.log(JSON.stringify(error.response.data, null, 2));
      }
    }
  }

  logInfo(`\nSemantic search success rate: ${successCount}/${searchQueries.length}`);
  return successCount === searchQueries.length;
}

// Test 5: Get Embeddings Stats
async function testEmbeddingsStats() {
  logTest('Test 5: Get User Embeddings Statistics');
  try {
    const response = await axios.get(`${BASE_URL}/test/embeddings/stats/test_user_123`);

    if (response.data.success) {
      const stats = response.data.data;
      logSuccess('Retrieved embeddings statistics');
      logInfo(`  Total embeddings: ${stats.totalEmbeddings}`);
      logInfo(`  Conversations with embeddings: ${stats.conversationsWithEmbeddings}`);
      logInfo(`  Topics distribution:`);
      Object.entries(stats.topicsDistribution).forEach(([topic, count]) => {
        logInfo(`    - ${topic}: ${count}`);
      });
      return true;
    } else {
      logError('Failed to retrieve stats');
      return false;
    }
  } catch (error) {
    logError(`Stats retrieval error: ${error.message}`);
    if (error.response?.data) {
      console.log(JSON.stringify(error.response.data, null, 2));
    }
    return false;
  }
}

// Test 6: Conversation with Semantic Memory
async function testConversationWithSemanticMemory() {
  logTest('Test 6: New Conversation Using Semantic Memory');
  try {
    logInfo('Creating follow-up question that should find semantic context...');

    const response = await axios.post(`${BASE_URL}/chat`, {
      message: "My baby is having trouble sleeping, any tips?"
    });

    if (response.data.success) {
      logSuccess('Conversation created with semantic context');
      logInfo(`AI Response: ${response.data.data.message.substring(0, 200)}...`);

      // Check if response seems contextual (contains sleep-related info)
      const responseText = response.data.data.message.toLowerCase();
      if (responseText.includes('sleep') || responseText.includes('nap')) {
        logSuccess('Response appears to use semantic context (mentions sleep)');
        return true;
      } else {
        logInfo('Response created, but semantic context usage unclear');
        return true;
      }
    } else {
      logError('Conversation creation failed');
      return false;
    }
  } catch (error) {
    logError(`Semantic memory test error: ${error.message}`);
    if (error.response?.data) {
      console.log(JSON.stringify(error.response.data, null, 2));
    }
    return false;
  }
}

// Main test runner
async function runTests() {
  console.log(`\n${colors.yellow}╔════════════════════════════════════════════════╗${colors.reset}`);
  console.log(`${colors.yellow}║  Embeddings-Based Conversation Memory Tests   ║${colors.reset}`);
  console.log(`${colors.yellow}╚════════════════════════════════════════════════╝${colors.reset}\n`);

  const results = {
    total: 6,
    passed: 0,
    failed: 0
  };

  // Test 1: Health Check
  if (await testHealthCheck()) {
    results.passed++;
  } else {
    results.failed++;
    logError('Health check failed - stopping tests');
    return results;
  }

  await sleep(500);

  // Test 2: Generate Embedding
  if (await testGenerateEmbedding()) {
    results.passed++;
  } else {
    results.failed++;
  }

  await sleep(500);

  // Test 3: Create Conversations
  const conversationIds = await testCreateConversationWithEmbeddings();
  if (conversationIds.length > 0) {
    results.passed++;
  } else {
    results.failed++;
  }

  await sleep(2000); // Wait for embeddings to be stored

  // Test 4: Semantic Search
  if (await testSemanticSearch(conversationIds)) {
    results.passed++;
  } else {
    results.failed++;
  }

  await sleep(500);

  // Test 5: Embeddings Stats
  if (await testEmbeddingsStats()) {
    results.passed++;
  } else {
    results.failed++;
  }

  await sleep(500);

  // Test 6: Semantic Memory
  if (await testConversationWithSemanticMemory()) {
    results.passed++;
  } else {
    results.failed++;
  }

  // Summary
  console.log(`\n${colors.yellow}╔════════════════════════════════════════════════╗${colors.reset}`);
  console.log(`${colors.yellow}║              Test Summary                      ║${colors.reset}`);
  console.log(`${colors.yellow}╚════════════════════════════════════════════════╝${colors.reset}\n`);

  log('blue', `Total tests: ${results.total}`);
  log('green', `Passed: ${results.passed}`);
  if (results.failed > 0) {
    log('red', `Failed: ${results.failed}`);
  } else {
    log('green', `Failed: ${results.failed}`);
  }

  const successRate = ((results.passed / results.total) * 100).toFixed(1);
  console.log();
  if (results.failed === 0) {
    log('green', `✓ All tests passed! (${successRate}%)`);
  } else {
    log('yellow', `⚠ Some tests failed (${successRate}% success rate)`);
  }
  console.log();

  return results;
}

// Run tests
runTests().catch(error => {
  logError(`Fatal error: ${error.message}`);
  console.error(error);
  process.exit(1);
});
