import { test, expect } from '@playwright/test';
import { detectQueryType, getSearchWeights } from '../../lib/utils';
import { QueryType } from '../../lib/types';

test.describe('Query Type Detection Tests', () => {
  test('should detect exact queries with quotes', () => {
    expect(detectQueryType('"Error 404"')).toBe('exact');
    expect(detectQueryType("'exact phrase'")).toBe('exact');
    expect(detectQueryType('"multiple words"')).toBe('exact');
  });

  test('should detect conceptual queries', () => {
    // Question words
    expect(detectQueryType('how to cook pasta')).toBe('conceptual');
    expect(detectQueryType('what is python')).toBe('conceptual');
    expect(detectQueryType('where to find')).toBe('conceptual');
    expect(detectQueryType('why does this happen')).toBe('conceptual');
    expect(detectQueryType('who invented')).toBe('conceptual');

    // Conceptual phrases
    expect(detectQueryType('ways to improve')).toBe('conceptual');
    expect(detectQueryType('best way to learn')).toBe('conceptual');
    expect(detectQueryType('guide for beginners')).toBe('conceptual');
    expect(detectQueryType('tips for cooking')).toBe('conceptual');
    expect(detectQueryType('learn about javascript')).toBe('conceptual');
    expect(detectQueryType('understand recursion')).toBe('conceptual');

    // Learning patterns
    expect(detectQueryType('tutorial on react')).toBe('conceptual');
    expect(detectQueryType('guide to typescript')).toBe('conceptual');
    expect(detectQueryType('introduction to python')).toBe('conceptual');
    expect(detectQueryType('overview of microservices')).toBe('conceptual');
    expect(detectQueryType('explanation of quantum computing')).toBe('conceptual');
    expect(detectQueryType('examples of callbacks')).toBe('conceptual');
  });

  test('should detect mixed queries', () => {
    // Simple terms
    expect(detectQueryType('javascript')).toBe('mixed');
    expect(detectQueryType('programming')).toBe('mixed');
    expect(detectQueryType('cooking')).toBe('mixed');

    // Multiple words without patterns
    expect(detectQueryType('javascript programming')).toBe('mixed');
    expect(detectQueryType('react components')).toBe('mixed');
    expect(detectQueryType('database design')).toBe('mixed');
  });

  test('should be case-insensitive', () => {
    expect(detectQueryType('How To Cook')).toBe('conceptual');
    expect(detectQueryType('WHAT IS PYTHON')).toBe('conceptual');
    expect(detectQueryType('"Error 404"')).toBe('exact');
  });

  test('should handle empty and whitespace queries', () => {
    expect(detectQueryType('')).toBe('mixed');
    expect(detectQueryType('   ')).toBe('mixed');
  });
});

test.describe('Search Weight Calculation Tests', () => {
  test('should return correct weights for exact queries', () => {
    const weights = getSearchWeights('exact');

    expect(weights.keywordWeight).toBe(2.0);
    expect(weights.semanticWeight).toBe(0.7);
  });

  test('should return correct weights for conceptual queries', () => {
    const weights = getSearchWeights('conceptual');

    expect(weights.keywordWeight).toBe(0.7);
    expect(weights.semanticWeight).toBe(1.5);
  });

  test('should return correct weights for mixed queries', () => {
    const weights = getSearchWeights('mixed');

    expect(weights.keywordWeight).toBe(1.0);
    expect(weights.semanticWeight).toBe(1.0);
  });

  test('should handle unknown query type as mixed', () => {
    const weights = getSearchWeights('unknown' as QueryType);

    expect(weights.keywordWeight).toBe(1.0);
    expect(weights.semanticWeight).toBe(1.0);
  });
});

test.describe('Adaptive Weighting Integration Tests', () => {
  test('exact query boosts keyword matches', () => {
    const queryType = detectQueryType('"exact phrase"');
    const weights = getSearchWeights(queryType);

    // Keyword matches should be 2x more important
    expect(weights.keywordWeight).toBeGreaterThan(weights.semanticWeight);
    expect(weights.keywordWeight / weights.semanticWeight).toBeCloseTo(2.0 / 0.7, 1);
  });

  test('conceptual query boosts semantic matches', () => {
    const queryType = detectQueryType('how to cook');
    const weights = getSearchWeights(queryType);

    // Semantic matches should be more important
    expect(weights.semanticWeight).toBeGreaterThan(weights.keywordWeight);
    expect(weights.semanticWeight / weights.keywordWeight).toBeCloseTo(1.5 / 0.7, 1);
  });

  test('mixed query treats both equally', () => {
    const queryType = detectQueryType('javascript programming');
    const weights = getSearchWeights(queryType);

    // Both should have equal weight
    expect(weights.keywordWeight).toBe(weights.semanticWeight);
    expect(weights.keywordWeight).toBe(1.0);
  });

  test('weights significantly affect ranking scores', () => {
    const k = 20;
    const rank = 5;

    // Same rank with different weights
    const exactQueryScore = (1 / (k + rank)) * 2.0; // keyword
    const conceptualQueryScore = (1 / (k + rank)) * 1.5; // semantic

    // Exact keyword match should get highest score
    expect(exactQueryScore).toBeGreaterThan(conceptualQueryScore);
  });
});

test.describe('Weight Impact on Scenarios', () => {
  test('scenario 1: User searches for "Error 404"', () => {
    const query = '"Error 404"';
    const queryType = detectQueryType(query);
    const weights = getSearchWeights(queryType);

    // Should be exact match type
    expect(queryType).toBe('exact');

    // Keyword matches should be heavily prioritized
    expect(weights.keywordWeight).toBe(2.0);

    // Semantic matches should be deprioritized
    expect(weights.semanticWeight).toBe(0.7);

    // This ensures that notes with "Error 404" appear first,
    // even if semantic search might suggest other error types
  });

  test('scenario 2: User searches for "how to cook pasta"', () => {
    const query = 'how to cook pasta';
    const queryType = detectQueryType(query);
    const weights = getSearchWeights(queryType);

    // Should be conceptual type
    expect(queryType).toBe('conceptual');

    // Semantic matches should be boosted
    expect(weights.semanticWeight).toBe(1.5);

    // Keyword matches should be reduced
    expect(weights.keywordWeight).toBe(0.7);

    // This ensures that notes about cooking, pasta, recipes appear,
    // even if they don't contain the exact words "how to cook pasta"
  });

  test('scenario 3: User searches for "tutorial javascript"', () => {
    const query = 'tutorial javascript';
    const queryType = detectQueryType(query);
    const weights = getSearchWeights(queryType);

    // Should be conceptual type (starts with "tutorial")
    expect(queryType).toBe('conceptual');

    // Semantic search should be prioritized
    expect(weights.semanticWeight).toBeGreaterThan(weights.keywordWeight);
  });

  test('scenario 4: User searches for "react hooks"', () => {
    const query = 'react hooks';
    const queryType = detectQueryType(query);
    const weights = getSearchWeights(queryType);

    // Should be mixed type (no specific pattern)
    expect(queryType).toBe('mixed');

    // Both should have equal weight
    expect(weights.keywordWeight).toBe(weights.semanticWeight);
  });
});
