"""
Utility functions for validating prompt templates and their placeholders.
"""
import re
import logging
from typing import Dict, List, Set, Tuple
from django.utils.translation import gettext as _

logger = logging.getLogger(__name__)

# Define required placeholders for each divination type
REQUIRED_PLACEHOLDERS = {
    'bazi': {
        # Basic information
        'name', 'gender', 'birth_date', 'birth_time',
        
        # Year pillar
        'year_stem', 'year_branch', 'year_stem_element',
        'year_hidden_elements', 'year_stem_relationship',
        'year_hidden_relationships', 'year_sha_gods',
        
        # Month pillar
        'month_stem', 'month_branch', 'month_stem_element',
        'month_hidden_elements', 'month_stem_relationship',
        'month_hidden_relationships', 'month_sha_gods',
        
        # Day pillar
        'day_stem', 'day_branch', 'day_stem_element',
        'day_hidden_elements', 'day_hidden_relationships', 'day_sha_gods',
        
        # Hour pillar
        'hour_stem', 'hour_branch', 'hour_stem_element',
        'hour_hidden_elements', 'hour_stem_relationship',
        'hour_hidden_relationships', 'hour_sha_gods',
        
        # Element strengths
        'wood_strength', 'fire_strength', 'earth_strength',
        'metal_strength', 'water_strength',
        
        # Additional information
        'life_number', 'life_palace', 'current_age',
        'current_luck_pillar', 'current_year',
        'current_year_stem', 'current_year_branch'
    },
    'number': {
        # Basic information
        'name', 'gender', 'birth_date', 'birth_time',
        
        # Core Number Information
        'formula', 'personal_number', 'personality_title',
        'personal_element',
        
        # Number Chart Data
        'head_number', 'missing_numbers', 'present_numbers',
        'zodiac_name', 'zodiac_boost_numbers',
        
        # Element Analysis
        'element_counts', 'strongest_element', 'weakest_element',
        
        # Life Path Analysis
        'career_genes', 'career_process', 'career_result',
        'relationship_genes', 'relationship_process', 'relationship_result',
        'life_genes', 'life_process', 'life_result', 'hidden_gift',
        
        # Current Year
        'current_year', 'year_number', 'year_element',
        'year_element_relationship'
    },
    'liuyao': {
        # Basic information (always required)
        'question', 'qdate', 'hexagram_calculation'
    },
}

# Define optional placeholders for each divination type
OPTIONAL_PLACEHOLDERS = {
    'bazi': {
        # Optional placeholders (valid but not required)
        'day_stem_relationship',  # Always 'Self' since day stem is the day master
        # Future year placeholders
        'next_year', 'next_year_stem', 'next_year_branch',
        'next2_year', 'next2_year_stem', 'next2_year_branch'
    },
    'number': set(),  # All number placeholders are currently required
    'liuyao': {
        # Conditional placeholders (only used when relevant)
        'changing_lines', 'changing_lines_count',
        'changed_hexagram_info', 'changed_hexagram_number'
    },
}

def extract_placeholders(template_content: str) -> Set[str]:
    """
    Extract all placeholders from a template string.
    
    Args:
        template_content: The template content to analyze
        
    Returns:
        Set of placeholder names found in the template
    """
    # Match {{placeholder}} pattern
    pattern = r'{{([^}]+)}}'
    matches = re.findall(pattern, template_content)
    return {match.strip() for match in matches}

def validate_template(template_content: str, divination_type: str) -> Tuple[bool, List[str]]:
    """
    Validate a template against required placeholders.
    
    Args:
        template_content: The template content to validate
        divination_type: The type of divination (bazi, number, liuyao)
        
    Returns:
        Tuple of (is_valid, list_of_warnings)
    """
    warnings = []
    
    # Get required and optional placeholders for this divination type
    required = REQUIRED_PLACEHOLDERS.get(divination_type, set())
    optional = OPTIONAL_PLACEHOLDERS.get(divination_type, set())
    
    if not required:
        warnings.append(str(_(f"No required placeholders defined for {divination_type}")))
        return False, warnings
    
    # Extract placeholders from template
    found_placeholders = extract_placeholders(template_content)
    
    # For BaZi templates, treat all placeholders as optional
    if divination_type == 'bazi':
        # Check for potential syntax issues only
        if '{{' in template_content and '}}' not in template_content:
            warnings.append(str(_("Unclosed placeholder found")))
        if '}}' in template_content and '{{' not in template_content:
            warnings.append(str(_("Unopened placeholder found")))
        
        # Check for malformed placeholders
        malformed = re.findall(r'{{[^}]*[^a-zA-Z0-9_][^}]*}}', template_content)
        if malformed:
            warnings.append(str(_(f"Malformed placeholders found: {', '.join(malformed)}")))
        
        # For BaZi, provide informational messages about placeholders
        missing = required - found_placeholders
        if missing:
            logger.info(f"BaZi template could use these additional placeholders: {', '.join(sorted(missing))}")
        
        # Check for unused placeholders (informational only)
        allowed = required | optional
        unused = found_placeholders - allowed
        if unused:
            logger.info(f"BaZi template contains custom placeholders: {', '.join(sorted(unused))}")
        
        # Only fail validation if there are syntax errors
        has_syntax_errors = bool(malformed) or ('{{' in template_content and '}}' not in template_content) or ('}}' in template_content and '{{' not in template_content)
        return not has_syntax_errors, warnings
    
    else:
        # For other divination types, use the original strict validation
        # Check for missing required placeholders
        missing = required - found_placeholders
        if missing:
            warnings.append(str(_(f"Missing required placeholders: {', '.join(sorted(missing))}")))
        
        # Check for unused placeholders (not in required or optional)
        allowed = required | optional
        unused = found_placeholders - allowed
        if unused:
            warnings.append(str(_(f"Unused placeholders found: {', '.join(sorted(unused))}")))
        
        # Check for potential issues
        if '{{' in template_content and '}}' not in template_content:
            warnings.append(str(_("Unclosed placeholder found")))
        if '}}' in template_content and '{{' not in template_content:
            warnings.append(str(_("Unopened placeholder found")))
        
        # Check for malformed placeholders
        malformed = re.findall(r'{{[^}]*[^a-zA-Z0-9_][^}]*}}', template_content)
        if malformed:
            warnings.append(str(_(f"Malformed placeholders found: {', '.join(malformed)}")))
        
        return len(warnings) == 0, warnings

def get_template_statistics(template_content: str) -> Dict[str, int]:
    """
    Get statistics about a template.
    
    Args:
        template_content: The template content to analyze
        
    Returns:
        Dictionary with template statistics
    """
    placeholders = extract_placeholders(template_content)
    
    return {
        'total_placeholders': len(placeholders),
        'total_characters': len(template_content),
        'estimated_tokens': len(template_content) // 4,  # Rough approximation
    }

def log_template_change(template_id, user_id, action_type, warnings=None):
    """
    Log a change to a template.
    
    Args:
        template_id: ID of the template being changed
        user_id: ID of the user making the change
        action_type: Type of action (created, updated, archived, activated)
        warnings: List of warnings from validation
    """
    if warnings is None:
        warnings = []
    
    logger.info(
        f"Template {action_type} - ID: {template_id}, User: {user_id}, "
        f"Warnings: {', '.join(warnings) if warnings else 'None'}"
    )
    
    # Add more sophisticated logging here if needed
    # e.g., to a database or external monitoring system 