"""
Smart Consumption Extractor for Production
Uses database data + AI verification for accuracy
"""

import re
from typing import Dict, Optional
from sqlalchemy.orm import Session
from datetime import datetime

from src.utils.logger import get_logger

logger = get_logger(__name__)

class SmartConsumptionExtractor:
    """
    Extract consumption data from production database database
    Uses V2 logic patterns with AI verification
    """
    
    def __init__(self):
        self.dosage_patterns = {
            'QDS': ['qds', 'four times', '4 times', 'four-times'],
            'TDS': ['tds', 'thrice', 'three times', '3 times', 'ter in die'],
            'BD': ['bd', 'twice', 'two times', '2 times', 'bis in die', 'bid'],
            'OD': ['od', 'once daily', 'once a day', 'once-daily', 'quaque die', 'qd'],
            'OW': ['once weekly', 'once a week', 'once-weekly', 'per week', 'weekly'],
            'BW': ['twice weekly', 'twice a week', 'two times a week', '2 times a week', 'biweekly'],
            'OM': ['once monthly', 'once a month', 'once-monthly', 'monthly'],
            'OY': ['once yearly', 'once a year', 'once-yearly', 'annually', 'yearly', 'once per year'],
            'ONCE': ['single dose', 'one-time', 'one time only', 'once only', 'stat dose', 'stat'],
        }
        
        self.meal_patterns = {
            'Empty Stomach': ['empty stomach', 'before breakfast', '1 hour before food'],
            'Before Meal': ['before food', 'before meal', 'before eating', '30 minutes before food'],
            'After Meal': ['after food', 'after meal', 'after eating', 'with or after food'],
            'With Meal': ['with food', 'with meal', 'while eating', 'during meal'],
            'At Bedtime': ['bedtime', 'before sleep', 'at night', 'before sleeping']
        }
    
    def extract_from_database_record(self, medicine_record, enable_validation=True, use_ai_fallback=True) -> Dict:
        """
        Extract consumption data from database Medicine record

        Args:
            medicine_record: SQLAlchemy Medicine model instance
            enable_validation: Enable medical validation checks (default: True)
            use_ai_fallback: Enable Gemini AI fallback for low-confidence extractions (default: True)

        Returns:
            Dict with extracted consumption data
        """
        # Get all relevant fields
        how_to_use = str(medicine_record.how_to_use or "").lower()
        composition = str(medicine_record.salt_composition or "")
        primary_use = str(medicine_record.primary_use or "").lower()
        medicine_type = str(medicine_record.medicine_type or "").lower()

        # Extract each component
        quantity = self._extract_quantity(composition)
        dosage_code, dosage_explicit = self._extract_dosage_code(how_to_use, medicine_type)
        frequency = self._map_dosage_to_frequency(dosage_code)
        meal_preference = self._extract_meal_preference(how_to_use)
        duration = self._extract_duration(how_to_use, primary_use)

        # Calculate confidence score
        confidence = self._calculate_confidence(
            how_to_use, composition, dosage_code, meal_preference,
            dosage_explicit=dosage_explicit
        )

        # Build result dictionary
        result = {
            'medicine_name': medicine_record.product_name,
            'quantity': quantity,
            'dosage': dosage_code,
            'frequency': frequency,
            'meal_preference': meal_preference,
            'duration': duration,
            'confidence_score': confidence,
            'needs_verification': confidence < 0.80,
            'extraction_method': 'regex',
            'dosage_explicit': dosage_explicit,
        }

        # AI fallback for low-confidence extractions
        if use_ai_fallback and confidence < 0.85:
            try:
                from src.nlp.gemini_extractor import get_gemini_extractor
                gemini = get_gemini_extractor()
                if gemini.is_available():
                    ai_result = gemini.extract_dosage(
                        medicine_name=medicine_record.product_name,
                        composition=composition,
                        how_to_use=str(medicine_record.how_to_use or ""),
                        medicine_type=str(medicine_record.medicine_type or ""),
                        primary_use=str(medicine_record.primary_use or ""),
                    )
                    if ai_result and ai_result.get('confidence', 0) > confidence:
                        result['quantity'] = ai_result.get('quantity', quantity)
                        result['dosage'] = ai_result.get('dosage', dosage_code)
                        result['frequency'] = ai_result.get('frequency', frequency)
                        result['meal_preference'] = ai_result.get('meal_preference', meal_preference)
                        result['duration'] = ai_result.get('duration', duration)
                        result['confidence_score'] = ai_result.get('confidence', confidence)
                        result['needs_verification'] = False
                        result['extraction_method'] = 'gemini_ai'
                        logger.info(
                            f"AI improved extraction for {medicine_record.product_name}: "
                            f"conf {confidence:.2f} -> {result['confidence_score']:.2f}"
                        )
            except Exception as e:
                logger.warning(f"Gemini AI fallback failed for {medicine_record.product_name}: {e}")

        # Add validation if enabled
        if enable_validation:
            validation = self._validate_extraction(medicine_record, result)
            result['validation'] = validation
            result['is_safe'] = validation['is_safe']
            result['warnings'] = validation.get('warnings', [])

        return result
    
    def _validate_extraction(self, medicine_record, extracted_data) -> Dict:
        """NEW METHOD: Validate extracted data against medical standards"""
        warnings = []
        is_safe = True
        
        composition = (medicine_record.salt_composition or "").lower()
        medicine_type = (medicine_record.medicine_type or "").lower()
        dosage_code = extracted_data['dosage']
        
        # Check medicine type vs dosage consistency
        if 'syrup' in medicine_type or 'suspension' in medicine_type:
            if dosage_code == 'OD':
                warnings.append("Syrups/Suspensions are rarely OD - please verify")
        
        if 'injection' in medicine_type:
            if dosage_code in ['TDS', 'QDS']:
                warnings.append("Injections rarely given 3-4 times daily - please verify")
        
        if 'cream' in medicine_type or 'ointment' in medicine_type:
            if dosage_code == 'QDS':
                warnings.append("Topical applications rarely QDS - please verify")
        
        # Check for common medicine dosage limits
        paracetamol_keywords = ['paracetamol', 'acetaminophen', 'pcm']
        if any(keyword in composition for keyword in paracetamol_keywords):
            qty_match = re.search(r'(\d+)', extracted_data['quantity'])
            if qty_match:
                strength = int(qty_match.group(1))
                doses_per_day = {'OD': 1, 'BD': 2, 'TDS': 3, 'QDS': 4}
                daily_dose = strength * doses_per_day.get(dosage_code, 2)
                
                if daily_dose > 4000:
                    warnings.append(
                        f"Paracetamol daily dose ({daily_dose}mg) exceeds safe limit (4000mg)"
                    )
                    is_safe = False
        
        return {
            'is_safe': is_safe,
            'warnings': warnings,
            'validated': True,
            'validation_timestamp': datetime.now().isoformat()
        }
    
    def _extract_quantity(self, composition: str) -> str:
        """Extract dosage strength from composition"""
        if not composition or composition == 'nan':
            return "As prescribed"
        
        # Match: 500mg, 10mcg, 2.5g, 100ml, 1000IU, 5%
        patterns = [
            r'(\d+\.?\d*)\s*(mg/ml)',  # Liquid concentration
            r'(\d+\.?\d*)\s*(mg|mcg|g|ml|iu|%)',  # Standard units
            r'(\d+)\s*(tablet|capsule|pill)',  # Count-based
        ]
        
        for pattern in patterns:
            match = re.search(pattern, composition, re.IGNORECASE)
            if match:
                value = match.group(1)
                unit = match.group(2)
                return f"{value} {unit}"
        
        return "As prescribed"
    
    def _extract_dosage_code(self, how_to_use: str, medicine_type: str) -> tuple:
        """Extract dosage frequency code.

        Returns:
            tuple: (code, explicit) where explicit=True if matched from text,
                   False if it was a guessed default based on medicine type.
        """
        text = how_to_use.lower()

        # Check patterns in priority order
        for code, patterns in self.dosage_patterns.items():
            if any(pattern in text for pattern in patterns):
                return (code, True)

        # Smart defaults based on medicine type (not explicit)
        if any(x in medicine_type for x in ['syrup', 'suspension', 'drops']):
            return ("TDS", False)  # Liquids usually 3x daily
        elif any(x in medicine_type for x in ['injection', 'infusion', 'implant']):
            return ("OD", False)  # Injectable usually once
        elif any(x in medicine_type for x in ['ointment', 'cream', 'gel', 'lotion']):
            return ("BD", False)  # Topical usually 2x daily
        elif 'tablet' in medicine_type or 'capsule' in medicine_type:
            return ("BD", False)  # Default for oral solids

        return ("BD", False)  # Safe default
    
    def _map_dosage_to_frequency(self, dosage_code: str) -> str:
        """Map dosage code to human-readable frequency"""
        frequency_map = {
            'QDS': 'Four times daily',
            'TDS': 'Thrice daily',
            'BD': 'Twice daily',
            'OD': 'Once daily',
            'OW': 'Once weekly',
            'BW': 'Twice weekly',
            'OM': 'Once monthly',
            'OY': 'Once yearly',
            'ONCE': 'Single dose',
        }
        return frequency_map.get(dosage_code, 'Twice daily')
    
    def _extract_meal_preference(self, how_to_use: str) -> str:
        """Extract meal timing preference"""
        text = how_to_use.lower()
        
        # Check patterns in priority order
        for preference, patterns in self.meal_patterns.items():
            if any(pattern in text for pattern in patterns):
                return preference
        
        # Check for generic mentions
        if 'food' in text or 'meal' in text:
            return "With Meal"  # Generic food mention
        
        return "As advised"
    
    def _extract_duration(self, how_to_use: str, primary_use: str) -> str:
        """Extract treatment duration with smart defaults"""
        combined = f"{how_to_use} {primary_use}".lower()
        
        # Direct duration pattern: "5-7 days", "2 weeks", "3 months"
        duration_match = re.search(
            r'(?:for\s+)?(\d+)(?:\s*(?:to|-)\s*(\d+))?\s*(day|week|month)s?',
            combined,
            re.IGNORECASE
        )
        
        if duration_match:
            start = duration_match.group(1)
            end = duration_match.group(2)
            unit = duration_match.group(3)
            if end:
                return f"{start}-{end} {unit}s"
            return f"{start} {unit}{'s' if int(start) > 1 else ''}"
        
        # Condition-based smart defaults
        conditions = {
            'antibiotic': '5-7 days',
            'bacterial': '7-10 days',
            'infection': '7 days',
            'pain': '3-5 days',
            'fever': '3-5 days',
            'cold': '5-7 days',
            'cough': '7 days',
            'allergy': '7-14 days',
            'diabetes': 'Long-term',
            'hypertension': 'Long-term',
            'cholesterol': 'Long-term',
            'chronic': 'Long-term',
            'acid reflux': '4-8 weeks',
            'ulcer': '4-8 weeks'
        }
        
        for condition, duration in conditions.items():
            if condition in combined:
                return duration
        
        return "As prescribed"
    
    def _calculate_confidence(
        self,
        how_to_use: str,
        composition: str,
        dosage_code: str,
        meal_preference: str,
        dosage_explicit: bool = True
    ) -> float:
        """
        Calculate confidence score for extracted data
        1.0 = Very confident, 0.0 = No confidence
        """
        confidence = 0.0

        # Base confidence from data availability
        if how_to_use and len(how_to_use) > 20:
            confidence += 0.30

        if composition and composition != 'nan':
            confidence += 0.20

        # Confidence from specific extractions
        # Only award full points if dosage was explicitly matched from text
        if dosage_code in ['OD', 'BD', 'TDS', 'QDS']:
            if dosage_explicit:
                confidence += 0.25
            else:
                confidence += 0.05  # Small credit for type-based guess

        if meal_preference != "As advised":
            confidence += 0.15

        # Penalty for defaults
        if how_to_use and 'as directed' in how_to_use.lower():
            confidence -= 0.10

        return min(max(confidence, 0.0), 1.0)


# Singleton instance
_extractor_instance = None

def get_smart_extractor():
    """Get singleton smart extractor"""
    global _extractor_instance
    if _extractor_instance is None:
        _extractor_instance = SmartConsumptionExtractor()
    return _extractor_instance
