"""
Number Power analysis utilities for AI processing.

This module provides functions to prepare data for AI analysis of Number Power charts.
"""
import logging
import json
from django.utils import timezone
from ai.models import PromptTemplate
from ai.services.factory import LLMServiceFactory
from iching.utils.utils import filter_prompt_for_response

logger = logging.getLogger(__name__)

# Map number to personality title
NUMBER_PERSONALITY = {
    1: "自信 (Confidence)",
    2: "妥协 (Compromise)",
    3: "选择 (Choice)",
    4: "成功 (Success)",
    5: "自由 (Freedom)",
    6: "平静 (Calmness)",
    7: "洞察 (Insight)",
    8: "利他 (Altruism)",
    9: "机会/成功 (Opportunity/Success)"
}

# Elements in Chinese and English
ELEMENT_NAMES = {
    "wood": "木",
    "fire": "火",
    "earth": "土",
    "metal": "金",
    "water": "水"
}

# Chinese zodiac names
ZODIAC_NAMES = {
    0: "鼠 (Rat)",
    1: "牛 (Ox)",
    2: "虎 (Tiger)",
    3: "兔 (Rabbit)",
    4: "龙 (Dragon)",
    5: "蛇 (Snake)",
    6: "马 (Horse)",
    7: "羊 (Goat)",
    8: "猴 (Monkey)",
    9: "鸡 (Rooster)",
    10: "狗 (Dog)",
    11: "猪 (Pig)"
}

def get_personality_title(number):
    """Get personality title for a number."""
    return NUMBER_PERSONALITY.get(number, f"Unknown ({number})")

def get_element_profile(element):
    """Get element profile description in Chinese."""
    profiles = {
        "wood": "生长性、适应性、灵活性、扩展性",
        "fire": "热情、有活力、表现力强、充满活力",
        "earth": "稳定、滋养、支持、扎根",
        "metal": "精确、有结构、有条理、专注",
        "water": "流动、直觉、适应性强、灵活"
    }
    return profiles.get(element, f"未知元素: {element}")

def get_zodiac_name(zodiac_number):
    """Get Chinese zodiac name for a number."""
    try:
        number = int(zodiac_number)
        return ZODIAC_NAMES.get(number, f"未知生肖 ({number})")
    except (ValueError, TypeError):
        return f"未知生肖 ({zodiac_number})"

def get_element_relationship(personal_element, year_element):
    """Get the relationship between personal element and year element in Chinese."""
    # Element generating relationships (productive cycle)
    generates = {
        "wood": "fire",
        "fire": "earth",
        "earth": "metal",
        "metal": "water",
        "water": "wood"
    }
    
    # Element controlling relationships (controlling cycle)
    controls = {
        "wood": "earth",
        "earth": "water",
        "water": "fire",
        "fire": "metal",
        "metal": "wood"
    }
    
    if year_element == personal_element:
        return f"同元素（相互增强）"
    elif generates[personal_element] == year_element:
        return f"您的五行（{ELEMENT_NAMES.get(personal_element, personal_element)}）生成年份五行（{ELEMENT_NAMES.get(year_element, year_element)}）"
    elif generates[year_element] == personal_element:
        return f"年份五行（{ELEMENT_NAMES.get(year_element, year_element)}）生成您的五行（{ELEMENT_NAMES.get(personal_element, personal_element)}）"
    elif controls[personal_element] == year_element:
        return f"您的五行（{ELEMENT_NAMES.get(personal_element, personal_element)}）克制年份五行（{ELEMENT_NAMES.get(year_element, year_element)}）"
    elif controls[year_element] == personal_element:
        return f"年份五行（{ELEMENT_NAMES.get(year_element, year_element)}）克制您的五行（{ELEMENT_NAMES.get(personal_element, personal_element)}）"
    else:
        return "中性关系"

def format_number_pairs(pairs):
    """Format number pairs for display."""
    if not pairs or len(pairs) < 13:
        return {
            "career_genes": "N/A",
            "career_process": "N/A - N/A",
            "career_result": "N/A",
            "relationship_genes": "N/A",
            "relationship_process": "N/A - N/A", 
            "relationship_result": "N/A",
            "life_genes": "N/A",
            "life_process": "N/A - N/A",
            "life_result": "N/A",
            "hidden_gift": "N/A"
        }
    
    return {
        # Career
        "career_genes": pairs[0],
        "career_process": f"{pairs[1]} - {pairs[2]}",
        "career_result": pairs[3],
        # Relationships
        "relationship_genes": pairs[4],
        "relationship_process": f"{pairs[5]} - {pairs[6]}",
        "relationship_result": pairs[7],
        # Life
        "life_genes": pairs[8],
        "life_process": f"{pairs[9]} - {pairs[10]}",
        "life_result": pairs[11],
        # Hidden gift
        "hidden_gift": pairs[12]
    }

def prepare_number_prompt(person, custom_template=None):
    """
    Prepare a prompt for number power analysis.
    
    Args:
        person: Person instance with number_result
        custom_template: Optional custom template to use
        
    Returns:
        str: Formatted prompt
    """
    # Check if person has number result
    if not person.number_result:
        logger.error(f"Cannot prepare number analysis prompt: Person {person.name} ({person.id}) has no number_result")
        return None
    
    # Get number data
    number_data = person.number_result
    
    # Get the active template or use custom template
    template_content = custom_template
    if not template_content:
        try:
            template = PromptTemplate.objects.get(divination_type='number', status='active')
            template_content = template.content
        except PromptTemplate.DoesNotExist:
            logger.error("No active template found for number analysis")
            return None
        except Exception as e:
            logger.error(f"Error retrieving template: {e}")
            return None
    
    # Format data for template
    replacements = {}
    
    # Basic information
    replacements['{{name}}'] = person.name
    replacements['{{gender}}'] = person.get_gender_display()
    replacements['{{birth_date}}'] = person.birth_date.strftime("%Y-%m-%d")
    replacements['{{birth_time}}'] = person.birth_time.strftime("%H:%M") if person.birth_time else "未知"
    
    # Core number information
    replacements['{{formula}}'] = number_data.get('formula', '未知')
    personal_number = number_data.get('number', 0)
    replacements['{{personal_number}}'] = str(personal_number)
    replacements['{{personality_title}}'] = get_personality_title(personal_number)
    
    # Element information
    personal_element = number_data.get('number_5e', 'unknown')
    replacements['{{personal_element}}'] = ELEMENT_NAMES.get(personal_element, personal_element)
    
    # Number chart data
    replacements['{{head_number}}'] = str(number_data.get('head', '未知'))
    replacements['{{missing_numbers}}'] = ', '.join(str(n) for n in number_data.get('no_nos', []))
    replacements['{{present_numbers}}'] = ', '.join(str(n) for n in number_data.get('have_nos', []))
    
    # Special information
    zodiac_number = number_data.get('zodiac', '未知')
    replacements['{{zodiac_name}}'] = get_zodiac_name(zodiac_number)
    zodiac_boost = number_data.get('zodiac_boost', [])
    replacements['{{zodiac_boost_numbers}}'] = ', '.join(zodiac_boost) if zodiac_boost else "无"
    
    # Element Analysis
    element_counts = number_data.get('number_5ec', {})
    formatted_element_counts = []
    strongest_element = "未知"
    weakest_element = "未知"
    
    if element_counts:
        max_count = 0
        min_count = float('inf')
        
        for element_num, count in element_counts.items():
            element_name = ELEMENT_NAMES.get(list(ELEMENT_NAMES.keys())[int(element_num)-1], f"元素 {element_num}")
            formatted_element_counts.append(f"{element_name}: {count}")
            
            if count > max_count:
                max_count = count
                strongest_element = element_name
                
            if count < min_count and count > 0:
                min_count = count
                weakest_element = element_name
    
    replacements['{{element_counts}}'] = ', '.join(formatted_element_counts)
    replacements['{{strongest_element}}'] = strongest_element
    replacements['{{weakest_element}}'] = weakest_element
    
    # Life Path Analysis
    pairs = number_data.get('pairs81', [])
    formatted_pairs = format_number_pairs(pairs)
    
    for key, value in formatted_pairs.items():
        replacements[f'{{{{{key}}}}}'] = value
    
    # Current Year information
    current_year = timezone.now().year
    replacements['{{current_year}}'] = str(current_year)
    
    year_number = number_data.get('year_number', 0)
    replacements['{{year_number}}'] = str(year_number)
    
    year_element = number_data.get('year_5e', 'unknown')
    replacements['{{year_element}}'] = ELEMENT_NAMES.get(year_element, year_element)
    
    # Relationship between personal element and year element
    replacements['{{year_element_relationship}}'] = get_element_relationship(personal_element, year_element)
    
    # Replace all placeholders in the template
    for placeholder, value in replacements.items():
        if value is None:
            logger.warning(f"Placeholder {placeholder} has None value")
            template_content = template_content.replace(placeholder, "未知")
        else:
            template_content = template_content.replace(placeholder, value)
    
    return template_content 

def analyze_number(person, model_key=None, provider=None):
    """
    Analyze a person's Number Power chart using AI.
    
    This function uses the active template from the database if available,
    otherwise falls back to the file system template.
    
    Args:
        person: Person object to analyze
        model_key: Optional model key to use (from settings.GROQ_MODELS or settings.OPENAI_MODELS)
        provider: Optional LLM provider to use ('groq' or 'openai')
        
    Returns:
        Dictionary with analysis results
    """
    try:
        # Get AI configuration for number if not provided
        if not provider or not model_key:
            from ai.utils.config import get_ai_config
            config = get_ai_config('number')
            provider = provider or config['provider']
            model_key = model_key or config['model']
        
        logger.info(f"Starting Number analysis for person id={person.id} using provider={provider}, model={model_key}")
        try:
            llm_service = LLMServiceFactory.get_service(provider)
            logger.debug(f"Created LLM service: {llm_service.__class__.__name__}")
        except Exception as e:
            logger.error(f"Failed to create LLM service: {str(e)}")
            raise ValueError(f"Could not initialize LLM service: {str(e)}")
        if model_key:
            try:
                llm_service.change_model(model_key)
                logger.debug(f"Changed model to {model_key}")
            except Exception as e:
                logger.error(f"Failed to change model to {model_key}: {str(e)}")
                raise ValueError(f"Could not change model to {model_key}: {str(e)}")
        try:
            prompt = prepare_number_prompt(person)
            logger.debug(f"Prepared Number prompt using active template, length: {len(prompt)} characters")
        except Exception as e:
            logger.error(f"Failed to prepare Number prompt: {str(e)}")
            raise ValueError(f"Could not prepare Number prompt: {str(e)}")
        try:
            logger.debug(f"Requesting LLM completion")
            raw_analysis = llm_service.get_completion(
                prompt=prompt,
                temperature=0.7,
                max_tokens=4096
            )
            logger.debug(f"Received LLM response, length: {len(raw_analysis) if raw_analysis else 0} characters")
            if not raw_analysis:
                logger.error("LLM returned empty response")
                raise ValueError("Empty response from LLM service")
        except Exception as e:
            logger.error(f"Failed to get LLM completion: {str(e)}")
            raise ValueError(f"Error getting completion from LLM service: {str(e)}")
        analysis = raw_analysis.strip()
        thinking_content = None
        import re
        try:
            thinking_match = re.search(r'<think>(.*?)</think>', analysis, re.DOTALL)
            if thinking_match:
                thinking_content = thinking_match.group(1).strip()
                analysis = re.sub(r'<think>.*?</think>', '', analysis, flags=re.DOTALL).strip()
                logger.debug(f"Extracted thinking content, length: {len(thinking_content)} characters")
            backticks_match = re.search(r'```(?:json)?(.*?)```', analysis, re.DOTALL)
            if backticks_match:
                backticks_content = backticks_match.group(1).strip()
                analysis = backticks_content
                logger.debug("Extracted content from backticks")
            try:
                json_data = json.loads(analysis)
                analysis = json_data
                logger.debug("Successfully parsed analysis as JSON")
            except json.JSONDecodeError as json_err:
                logger.warning(f"Analysis not valid JSON, using as string: {str(json_err)}")
        except Exception as e:
            logger.error(f"Failed to process LLM response: {str(e)}")
            logger.error(f"Raw analysis: {raw_analysis[:100]}...")
            raise ValueError(f"Error processing LLM response: {str(e)}")
        try:
            used_model = getattr(llm_service, 'model', model_key or "unknown")
            used_provider = provider
            logger.debug(f"Used model: {used_model}, provider: {used_provider}")
        except Exception as e:
            logger.error(f"Failed to get model information: {str(e)}")
            used_model = model_key or "unknown"
            used_provider = provider or "unknown"
        try:
            ai_analysis = {
                'number_analysis': analysis,
                'prompt': filter_prompt_for_response(prompt),
                'provider': used_provider,
                'model': used_model
            }
            if thinking_content:
                ai_analysis['think'] = thinking_content
            logger.debug(f"Prepared AI analysis dictionary with keys: {', '.join(ai_analysis.keys())}")
        except Exception as e:
            logger.error(f"Failed to prepare ai_analysis dictionary: {str(e)}")
            raise ValueError(f"Error preparing analysis dictionary: {str(e)}")
        try:
            person.number_ai_analysis = ai_analysis
            person.number_analysis_timestamp = timezone.now()
            person.number_analysis_status = 'completed'
            person.save(update_fields=['number_ai_analysis', 'number_analysis_timestamp', 'number_analysis_status'])
            logger.info(f"Successfully saved number analysis for person id={person.id}")
        except Exception as e:
            logger.error(f"Failed to save analysis to person object: {str(e)}")
            raise ValueError(f"Error saving analysis to database: {str(e)}")
        return person.number_ai_analysis
    except Exception as e:
        logger.error(f"Error analyzing Number for person {person.id}: {str(e)}", exc_info=True)
        raise 