#!/usr/bin/env python3
"""
Test unified search vs BM25 baseline on 20 questions.
Runs both engines, compares results, reports quality metrics.
"""
import json
import sys
import time
import os

sys.path.insert(0, "/data/knowledge/maritime")
os.environ['OLLAMA_EMBED_URL'] = 'http://127.0.0.1:11435/api/embed'

# Load both engines
from search_engine import search as bm25_search
from search_unified import search as unified_search, _do_classify as classify_query

# 20 test questions covering all 5 types
QUESTIONS = [
    # fact (5)
    {"q": "2019年全国注册船员总数是多少？", "type": "fact", "expected_keywords": ["1659188", "船员"]},
    {"q": "船员适任证书的有效期是多少年？", "type": "fact", "expected_keywords": ["证书", "有效期"]},
    {"q": "琼州海峡船舶定线制是什么时候施行的？", "type": "fact", "expected_keywords": ["琼州海峡", "施行"]},
    {"q": "船舶进出港报告制度的法律依据是什么？", "type": "fact", "expected_keywords": ["进出港", "报告"]},
    {"q": "内河船舶船员培训机构有多少家？", "type": "fact", "expected_keywords": ["培训机构", "内河"]},
    # compare (4)
    {"q": "海上交通安全法与水污染防治法在船舶管理方面的规定有何异同？", "type": "compare", "expected_keywords": ["海上交通安全法", "水污染防治法"]},
    {"q": "对比2019年和2020年中国船员发展报告的主要变化", "type": "compare", "expected_keywords": ["2019", "2020", "船员"]},
    {"q": "国内航行船舶和国际航行船舶的检验要求有什么区别？", "type": "compare", "expected_keywords": ["国内", "国际", "检验"]},
    {"q": "海事局规范性文件与交通运输部规章有何区别？", "type": "compare", "expected_keywords": ["海事局", "交通运输部"]},
    # relation (4)
    {"q": "海事局的上级主管部门是哪个？", "type": "relation", "expected_keywords": ["海事局", "交通运输部"]},
    {"q": "船员适任证书制度依据哪些国际公约？", "type": "relation", "expected_keywords": ["适任证书", "STCW", "公约"]},
    {"q": "防治船舶污染海洋环境管理条例由谁制定？", "type": "relation", "expected_keywords": ["防治", "污染", "条例"]},
    {"q": "船舶检验机构的资质由哪个部门认可？", "type": "relation", "expected_keywords": ["检验", "资质", "认可"]},
    # synthesis (4)
    {"q": "请梳理中国海事法律法规的层级体系", "type": "synthesis", "expected_keywords": ["全国人大", "国务院", "交通运输部", "海事局"]},
    {"q": "总结船员管理方面的主要法规和政策", "type": "synthesis", "expected_keywords": ["船员", "管理", "法规"]},
    {"q": "概述海洋环境保护相关的法律框架", "type": "synthesis", "expected_keywords": ["海洋", "环境", "保护"]},
    {"q": "分析港口管理的法规体系", "type": "synthesis", "expected_keywords": ["港口", "管理"]},
    # temporal (3)
    {"q": "海上交通安全法最新修订是什么时候？", "type": "temporal", "expected_keywords": ["海上交通安全法", "修订"]},
    {"q": "船员培训管理规则的最新版本何时施行？", "type": "temporal", "expected_keywords": ["培训", "施行"]},
    {"q": "水污染防治法经历了哪些修订？", "type": "temporal", "expected_keywords": ["水污染防治法", "修订"]},
]

print("=" * 70)
print("  LambdaRAG Unified Search vs BM25 Baseline Test")
print("  20 questions × 2 engines")
print("=" * 70)

results = []
for i, q in enumerate(QUESTIONS):
    print(f"\n{'─' * 70}")
    print(f"Q{i+1} [{q['type']}] {q['q']}")

    # Classify
    classified = classify_query(q['q'])
    classify_correct = classified == q['type']

    # BM25 baseline
    t0 = time.time()
    try:
        bm25_results = bm25_search(q['q'], top_k=5)
    except Exception as e:
        bm25_results = []
        print(f"  BM25 ERROR: {e}")
    bm25_time = time.time() - t0

    # Unified
    t0 = time.time()
    try:
        unified_results = unified_search(q['q'], top_k=5)
    except Exception as e:
        unified_results = []
        print(f"  UNIFIED ERROR: {e}")
    unified_time = time.time() - t0

    # Quality check: do results contain expected keywords?
    def check_relevance(search_results, keywords):
        if not search_results:
            return 0, []
        all_text = ' '.join([r.get('text', '') + ' ' + r.get('source', '') for r in search_results])
        found = [kw for kw in keywords if kw in all_text]
        return len(found) / max(len(keywords), 1), found

    bm25_score, bm25_found = check_relevance(bm25_results, q['expected_keywords'])
    unified_score, unified_found = check_relevance(unified_results, q['expected_keywords'])

    # Get unified metadata
    u_type = unified_results[0].get('_query_type', '?') if unified_results else '?'
    u_strategy = unified_results[0].get('_strategy', '?') if unified_results else '?'

    print(f"  Classify: predicted={classified} expected={q['type']} {'✓' if classify_correct else '✗'}")
    print(f"  BM25:    {bm25_time:.2f}s | relevance={bm25_score:.0%} | found={bm25_found}")
    print(f"  Unified: {unified_time:.2f}s | relevance={unified_score:.0%} | found={unified_found}")
    print(f"  Route:   {u_type} → {u_strategy}")

    # Check: unified sources different from BM25?
    bm25_sources = set(r.get('source', '')[:30] for r in bm25_results[:3])
    unified_sources = set(r.get('source', '')[:30] for r in unified_results[:3])
    sources_differ = bm25_sources != unified_sources

    record = {
        'id': i + 1,
        'question': q['q'],
        'expected_type': q['type'],
        'classified_type': classified,
        'classify_correct': classify_correct,
        'bm25_time': round(bm25_time, 2),
        'unified_time': round(unified_time, 2),
        'bm25_relevance': round(bm25_score, 2),
        'unified_relevance': round(unified_score, 2),
        'bm25_results_count': len(bm25_results),
        'unified_results_count': len(unified_results),
        'sources_differ': sources_differ,
        'unified_route': f"{u_type} → {u_strategy}",
        'winner': 'unified' if unified_score > bm25_score else ('tie' if unified_score == bm25_score else 'bm25'),
    }
    results.append(record)

# Summary
print(f"\n{'=' * 70}")
print("  SUMMARY")
print(f"{'=' * 70}")

# Classification accuracy
correct = sum(1 for r in results if r['classify_correct'])
print(f"\nClassification accuracy: {correct}/{len(results)} ({correct/len(results)*100:.0f}%)")

# Relevance comparison
bm25_avg = sum(r['bm25_relevance'] for r in results) / len(results)
unified_avg = sum(r['unified_relevance'] for r in results) / len(results)
print(f"\nRelevance (keyword match):")
print(f"  BM25 avg:    {bm25_avg:.0%}")
print(f"  Unified avg: {unified_avg:.0%}")

# Winner counts
wins = {'unified': 0, 'bm25': 0, 'tie': 0}
for r in results:
    wins[r['winner']] += 1
print(f"\nWins: Unified={wins['unified']} BM25={wins['bm25']} Tie={wins['tie']}")

# By type
print(f"\nBy question type:")
for qtype in ['fact', 'compare', 'relation', 'synthesis', 'temporal']:
    type_results = [r for r in results if r['expected_type'] == qtype]
    if not type_results:
        continue
    b_avg = sum(r['bm25_relevance'] for r in type_results) / len(type_results)
    u_avg = sum(r['unified_relevance'] for r in type_results) / len(type_results)
    wins_u = sum(1 for r in type_results if r['winner'] == 'unified')
    wins_b = sum(1 for r in type_results if r['winner'] == 'bm25')
    print(f"  {qtype:10s}: BM25={b_avg:.0%} Unified={u_avg:.0%} | U wins={wins_u} B wins={wins_b}")

# Timing
bm25_avg_time = sum(r['bm25_time'] for r in results) / len(results)
unified_avg_time = sum(r['unified_time'] for r in results) / len(results)
print(f"\nAvg search time:")
print(f"  BM25:    {bm25_avg_time:.2f}s")
print(f"  Unified: {unified_avg_time:.2f}s")

# Sources differ
differ_count = sum(1 for r in results if r['sources_differ'])
print(f"\nSources differ in {differ_count}/{len(results)} questions")

# Issues
print(f"\nPotential issues:")
for r in results:
    if r['unified_results_count'] == 0:
        print(f"  Q{r['id']}: Unified returned 0 results!")
    if not r['classify_correct']:
        print(f"  Q{r['id']}: Misclassified as {r['classified_type']} (expected {r['expected_type']})")
    if r['unified_relevance'] < r['bm25_relevance']:
        print(f"  Q{r['id']}: Unified worse than BM25 ({r['unified_relevance']:.0%} vs {r['bm25_relevance']:.0%})")

# Save results
with open('/data/knowledge/maritime/test_unified_results.json', 'w') as f:
    json.dump(results, f, ensure_ascii=False, indent=2)
print(f"\nResults saved to test_unified_results.json")
