"""
Search Service - Singleton service quản lý Trie index

Service này:
- Load data từ JSON khi startup
- Build Trie index một lần duy nhất
- Cung cấp API search cho FastAPI
"""

import json
from pathlib import Path
from typing import List, Dict, Optional
import time

from search.trie import Trie


class SearchService:
    """
    Singleton service quản lý search engine
    
    Pattern: Singleton
    - Chỉ tạo 1 instance duy nhất
    - Load data & build index KHI STARTUP (không phải mỗi request)
    - Share instance cho tất cả requests
    """
    
    _instance: Optional['SearchService'] = None
    _initialized: bool = False
    
    def __new__(cls):
        """Singleton pattern: chỉ tạo 1 instance"""
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self):
        """Khởi tạo (chỉ chạy 1 lần)"""
        if SearchService._initialized:
            return
        
        self.trie: Optional[Trie] = None
        self.documents: List[str] = []
        self.is_ready: bool = False
        
        SearchService._initialized = True
    
    def initialize(self, data_path: str = "data/unique_work_contents.json", max_results: int = 20):
        """
        Load data và build index
        
        GỌI HÀM NÀY KHI FASTAPI STARTUP!
        
        Args:
            data_path: Đường dẫn file JSON
            max_results: Số kết quả tối đa
        """
        print("\n" + "=" * 80)
        print("🚀 INITIALIZING SEARCH SERVICE")
        print("=" * 80)
        
        start_time = time.time()
        
        # 1. Load documents
        print(f"\n📂 Loading data from: {data_path}")
        try:
            with open(data_path, 'r', encoding='utf-8') as f:
                self.documents = json.load(f)
            print(f"✓ Loaded {len(self.documents)} documents")
        except FileNotFoundError:
            print(f"❌ File not found: {data_path}")
            raise
        except Exception as e:
            print(f"❌ Error loading data: {e}")
            raise
        
        # 2. Build Trie index
        print(f"\n🔨 Building Trie index...")
        print(f"   - max_results: {max_results}")
        print(f"   - word_start_indexing: True")
        print(f"   - normalize: True")
        
        self.trie = Trie(max_results=max_results)
        
        for doc_id, doc in enumerate(self.documents):
            self.trie.insert(
                text=doc,
                doc_id=doc_id,
                score=1.0,
                index_word_starts=True,
                normalize=True
            )
            
            # Progress
            if (doc_id + 1) % 100 == 0:
                print(f"   ... indexed {doc_id + 1}/{len(self.documents)}")
        
        elapsed = time.time() - start_time
        
        # 3. Stats
        stats = self.trie.get_stats()
        
        print(f"\n✅ INITIALIZATION COMPLETE")
        print(f"   ⏱️  Time: {elapsed:.2f}s")
        print(f"   📊 Documents: {len(self.documents):,}")
        print(f"   🌳 Trie nodes: {stats['total_nodes']:,}")
        print(f"   💾 Memory: ~{stats['total_nodes'] * 0.5 / 1024:.1f} MB (estimated)")
        print("=" * 80 + "\n")
        
        self.is_ready = True
    
    def search(self, query: str, limit: int = 20) -> List[Dict]:
        """
        Search với query
        
        Args:
            query: Chuỗi tìm kiếm
            limit: Số kết quả tối đa
        
        Returns:
            List[Dict] với format:
            [
                {
                    'id': 0,
                    'text': 'Làm sạch nhà vệ sinh',
                    'score': 1.0
                },
                ...
            ]
        """
        if not self.is_ready or self.trie is None:
            raise RuntimeError("Search service not initialized. Call initialize() first.")
        
        # Search trong Trie
        results = self.trie.search_prefix(query, normalize=True)
        
        # Format results
        formatted_results = []
        for doc_id, score in results[:limit]:
            formatted_results.append({
                'id': doc_id,
                'text': self.documents[doc_id],
                'score': score
            })
        
        return formatted_results
    
    def get_document(self, doc_id: int) -> Optional[str]:
        """
        Lấy document theo ID
        
        Args:
            doc_id: ID của document
        
        Returns:
            Text của document hoặc None
        """
        if 0 <= doc_id < len(self.documents):
            return self.documents[doc_id]
        return None
    
    def get_stats(self) -> Dict:
        """
        Lấy thống kê
        
        Returns:
            Dict chứa stats
        """
        if not self.is_ready or self.trie is None:
            return {
                'status': 'not_ready',
                'documents': 0
            }
        
        trie_stats = self.trie.get_stats()
        
        return {
            'status': 'ready',
            'documents': len(self.documents),
            'trie_nodes': trie_stats['total_nodes'],
            'max_results': trie_stats['max_results'],
            'features': trie_stats['features']
        }


# Singleton instance
_search_service = SearchService()


def get_search_service() -> SearchService:
    """
    Lấy search service instance
    
    Dùng hàm này trong FastAPI dependency injection
    
    Returns:
        SearchService instance
    """
    return _search_service
