"""
Utility functions for glossary cleaning system
- Turkish character handling
- Qdrant client wrapper
- OpenAI embedding helper
- Logging functions
"""

import re
import os
import json
import logging
from typing import List, Dict, Optional, Tuple
from datetime import datetime

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# Turkish character mappings
TURKISH_CHARS = {
    'ç': 'c', 'Ç': 'C',
    'ğ': 'g', 'Ğ': 'G',
    'ı': 'i', 'I': 'I',
    'İ': 'I', 'i': 'i',
    'ö': 'o', 'Ö': 'O',
    'ş': 's', 'Ş': 'S',
    'ü': 'u', 'Ü': 'U'
}

# OCR error corrections (common OCR mistakes)
OCR_CORRECTIONS = {
    'ý': 'ı',
    'þ': 'ş',
    'Ý': 'İ',
    'Þ': 'Ş',
    'ð': 'ğ',
    'Ð': 'Ğ',
    'ý': 'ı',
    'ö': 'ö',  # Keep correct
    'ü': 'ü',  # Keep correct
    'ÿ': 'ı',
    '×': 'x',
    '÷': '/',
    ''': "'",
    ''': "'",
    '"': '"',
    '"': '"',
    '–': '-',
    '—': '-',
    '…': '...',
}

# Foreign language patterns
FOREIGN_PATTERNS = {
    'italian': re.compile(r'\b(il|della|degli|anelli|preferibilmente|lubrificare|vedere|sopra|regolare|sostituire|lato|nella|sono|essere|fare|avere)\b', re.IGNORECASE),
    'german': re.compile(r'\b(mit|und|oder|die|das|der|ist|sind|werden|haben|nicht|auch|für|auf)\b', re.IGNORECASE),
    'spanish': re.compile(r'\b(el|la|los|las|del|para|con|por|una|uno|que|como)\b', re.IGNORECASE),
}


def fix_ocr_errors(text: str) -> str:
    """Fix common OCR errors in text"""
    for wrong, correct in OCR_CORRECTIONS.items():
        text = text.replace(wrong, correct)
    return text


def normalize_turkish(text: str) -> str:
    """Normalize Turkish text - fix encoding issues"""
    text = fix_ocr_errors(text)
    return text


def to_lowercase_turkish(text: str) -> str:
    """Convert to lowercase preserving Turkish characters"""
    # Turkish specific: I -> ı, İ -> i
    text = text.replace('I', 'ı').replace('İ', 'i')
    return text.lower()


def detect_language(text: str) -> str:
    """Detect if text contains foreign language patterns"""
    for lang, pattern in FOREIGN_PATTERNS.items():
        if pattern.search(text):
            return lang
    
    # Check if mostly ASCII (potential English)
    turkish_chars = set('çğıöşüÇĞİÖŞÜ')
    has_turkish = any(c in turkish_chars for c in text)
    
    if not has_turkish and re.match(r'^[A-Za-z0-9\s\-\.,/\(\)]+$', text):
        words = text.split()
        if len(words) >= 3:
            return 'english'
    
    return 'turkish'


def is_valid_glossary_entry(source: str, target: str) -> Tuple[bool, str]:
    """
    Validate a glossary entry
    Returns: (is_valid, reason)
    """
    # Empty check
    if not source or not target:
        return False, "EMPTY_VALUE"
    
    if len(source.strip()) < 2 or len(target.strip()) < 2:
        return False, "TOO_SHORT"
    
    # OCR garbage check
    if re.search(r'[ÖýþÝÞ]{2,}', target):
        return False, "OCR_GARBAGE"
    
    # Foreign language in target
    target_lang = detect_language(target)
    if target_lang in ['italian', 'german', 'spanish']:
        return False, f"FOREIGN_LANG_{target_lang.upper()}"
    
    # Source is Turkish but target is English (wrong direction)
    source_has_turkish = any(c in 'çğıöşüÇĞİÖŞÜ' for c in source)
    target_lang = detect_language(target)
    if source_has_turkish and target_lang == 'english':
        return False, "WRONG_DIRECTION"
    
    # Multiple alternatives in target (comma separated options)
    if ',' in target and target.count(',') >= 2:
        parts = [p.strip() for p in target.split(',')]
        if all(len(p) < 20 for p in parts):
            return False, "MULTIPLE_ALTERNATIVES"
    
    # Length ratio check (source too short, target too long)
    if len(source) <= 3 and len(target) > 50:
        return False, "LENGTH_MISMATCH"
    
    return True, "OK"


class QdrantHelper:
    """Helper class for Qdrant operations"""
    
    def __init__(self, host: str = "10.10.10.25", port: int = 6333, collection: str = "machine_docs"):
        self.host = host
        self.port = port
        self.collection = collection
        self.client = None
        
    def connect(self):
        """Connect to Qdrant"""
        try:
            from qdrant_client import QdrantClient
            self.client = QdrantClient(host=self.host, port=self.port, timeout=30)
            info = self.client.get_collection(self.collection)
            logger.info(f"Connected to Qdrant: {info.points_count:,} vectors")
            return True
        except Exception as e:
            logger.error(f"Qdrant connection error: {e}")
            return False
    
    def search(self, query_vector: List[float], limit: int = 5) -> List[Dict]:
        """Search in Qdrant"""
        if not self.client:
            return []
        
        try:
            results = self.client.query_points(
                collection_name=self.collection,
                query=query_vector,
                limit=limit,
                with_payload=True
            )
            return [
                {
                    'score': r.score,
                    'payload': r.payload
                }
                for r in results.points
            ]
        except Exception as e:
            logger.error(f"Qdrant search error: {e}")
            return []


class OpenAIHelper:
    """Helper class for OpenAI embeddings"""
    
    def __init__(self, model: str = "text-embedding-3-large"):
        self.model = model
        self.client = None
        
    def connect(self):
        """Initialize OpenAI client"""
        try:
            from openai import OpenAI
            self.client = OpenAI()
            logger.info(f"OpenAI client initialized (model: {self.model})")
            return True
        except Exception as e:
            logger.error(f"OpenAI initialization error: {e}")
            return False
    
    def get_embedding(self, text: str) -> Optional[List[float]]:
        """Get embedding for text"""
        if not self.client:
            return None
        
        try:
            response = self.client.embeddings.create(
                input=text,
                model=self.model
            )
            return response.data[0].embedding
        except Exception as e:
            logger.error(f"Embedding error: {e}")
            return None
    
    def get_embeddings_batch(self, texts: List[str], batch_size: int = 100) -> List[Optional[List[float]]]:
        """Get embeddings for multiple texts"""
        if not self.client:
            return [None] * len(texts)
        
        results = []
        for i in range(0, len(texts), batch_size):
            batch = texts[i:i+batch_size]
            try:
                response = self.client.embeddings.create(
                    input=batch,
                    model=self.model
                )
                for item in response.data:
                    results.append(item.embedding)
            except Exception as e:
                logger.error(f"Batch embedding error: {e}")
                results.extend([None] * len(batch))
        
        return results


def load_config(config_path: str) -> Dict:
    """Load configuration from YAML file"""
    import yaml
    with open(config_path, 'r', encoding='utf-8') as f:
        return yaml.safe_load(f)


def save_json(data: any, filepath: str):
    """Save data to JSON file"""
    with open(filepath, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)


def load_json(filepath: str) -> any:
    """Load data from JSON file"""
    with open(filepath, 'r', encoding='utf-8') as f:
        return json.load(f)


def generate_timestamp() -> str:
    """Generate timestamp string"""
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

