# content_rules_scorer.py
"""
ProductContentRule-based scorer for validating title, description, and SEO fields
against database-defined rules (ProductContentRule model)
"""
import re
import logging
from typing import Dict, List, Tuple

logger = logging.getLogger(__name__)

class ContentRulesScorer:
    """
    Validates product content fields against ProductContentRule definitions
    This scorer checks: title, description, short_description, seo_title, seo_description
    """
    
    def __init__(self):
        self.supported_fields = [
            'title', 'description', 'short_description', 
            'seo_title', 'seo_description'
        ]
    
    def score_content_fields(
        self, 
        product: Dict, 
        content_rules: List[Dict]
    ) -> Dict:
        """
        Score all content fields based on ProductContentRule definitions
        
        Args:
            product: Product dict with title, description, seo_title, etc.
            content_rules: List of ProductContentRule dicts for the category
            
        Returns:
            Dict with scores, issues, suggestions per field
        """
        try:
            category = product.get('category', '')
            
            # Separate global and category-specific rules
            global_rules = [r for r in content_rules if not r.get('category')]
            category_rules = [r for r in content_rules if r.get('category') == category]
            
            # Merge rules (category-specific overrides global)
            merged_rules = {}
            for rule in global_rules:
                merged_rules[rule['field_name']] = rule
            for rule in category_rules:
                merged_rules[rule['field_name']] = rule
            
            field_scores = {}
            all_issues = []
            all_suggestions = []
            
            # Score each field
            for field_name in self.supported_fields:
                field_value = product.get(field_name, '')
                rule = merged_rules.get(field_name)
                
                if not rule:
                    # No rule defined for this field - skip or use defaults
                    field_scores[field_name] = 100.0
                    continue
                
                score, issues, suggestions = self._score_single_field(
                    field_name, field_value, rule, category
                )
                
                field_scores[field_name] = score
                all_issues.extend(issues)
                all_suggestions.extend(suggestions)
            
            # Calculate overall content score (weighted average)
            weights = {
                'title': 0.30,
                'description': 0.35,
                'short_description': 0.10,
                'seo_title': 0.15,
                'seo_description': 0.10
            }
            
            overall_score = sum(
                field_scores.get(field, 100.0) * weights.get(field, 0)
                for field in self.supported_fields
            )
            
            return {
                'overall_content_score': round(overall_score, 2),
                'field_scores': field_scores,
                'issues': all_issues,
                'suggestions': all_suggestions,
                'rules_applied': len(merged_rules)
            }
            
        except Exception as e:
            logger.error(f"Content rules scoring error: {e}", exc_info=True)
            return {
                'overall_content_score': 0.0,
                'field_scores': {},
                'issues': [f"Content scoring failed: {str(e)}"],
                'suggestions': []
            }
    
    def _score_single_field(
        self, 
        field_name: str, 
        field_value: str, 
        rule: Dict,
        category: str
    ) -> Tuple[float, List[str], List[str]]:
        """
        Score a single content field against its rule
        
        Returns:
            Tuple of (score, issues, suggestions)
        """
        issues = []
        suggestions = []
        score_components = []
        
        field_label = field_name.replace('_', ' ').title()
        
        # 1. Check if mandatory
        if rule.get('is_mandatory', False):
            if not field_value or not field_value.strip():
                issues.append(f"{field_label}: Required field is missing")
                suggestions.append(f"Add {field_label} - it's mandatory for {category}")
                return 0.0, issues, suggestions
            score_components.append(100.0)
        else:
            if not field_value or not field_value.strip():
                # Not mandatory and empty - neutral score
                return 100.0, issues, suggestions
            score_components.append(100.0)
        
        field_value = field_value.strip()
        
        # 2. Check character length constraints
        min_length = rule.get('min_length')
        max_length = rule.get('max_length')
        actual_length = len(field_value)
        
        if min_length and actual_length < min_length:
            issues.append(
                f"{field_label}: Too short ({actual_length} chars, minimum {min_length})"
            )
            suggestions.append(
                f"Expand {field_label} to at least {min_length} characters"
            )
            length_score = (actual_length / min_length) * 100
            score_components.append(length_score)
        elif max_length and actual_length > max_length:
            issues.append(
                f"{field_label}: Too long ({actual_length} chars, maximum {max_length})"
            )
            suggestions.append(
                f"Shorten {field_label} to {max_length} characters or less"
            )
            length_score = max(50.0, 100 - ((actual_length - max_length) / max_length * 50))
            score_components.append(length_score)
        else:
            score_components.append(100.0)
        
        # 3. Check word count constraints
        min_words = rule.get('min_word_count')
        max_words = rule.get('max_word_count')
        word_count = len(field_value.split())
        
        if min_words and word_count < min_words:
            issues.append(
                f"{field_label}: Too few words ({word_count} words, minimum {min_words})"
            )
            suggestions.append(
                f"Expand {field_label} to at least {min_words} words with more details"
            )
            word_score = (word_count / min_words) * 100
            score_components.append(word_score)
        elif max_words and word_count > max_words:
            issues.append(
                f"{field_label}: Too many words ({word_count} words, maximum {max_words})"
            )
            suggestions.append(
                f"Reduce {field_label} to {max_words} words or less"
            )
            word_score = max(50.0, 100 - ((word_count - max_words) / max_words * 50))
            score_components.append(word_score)
        else:
            score_components.append(100.0)
        
        # 4. Check required keywords (must_contain_keywords)
        must_contain = rule.get('must_contain_keywords', [])
        if must_contain:
            field_lower = field_value.lower()
            found_keywords = [kw for kw in must_contain if kw.lower() in field_lower]
            
            if not found_keywords:
                issues.append(
                    f"{field_label}: Must contain at least one of: {', '.join(must_contain)}"
                )
                suggestions.append(
                    f"Add one of these keywords to {field_label}: {', '.join(must_contain[:3])}"
                )
                keyword_score = 0.0
            else:
                keyword_score = 100.0
            
            score_components.append(keyword_score)
        
        # 5. Check regex validation pattern
        validation_regex = rule.get('validation_regex')
        if validation_regex:
            try:
                if not re.match(validation_regex, field_value):
                    issues.append(
                        f"{field_label}: Format does not match required pattern"
                    )
                    suggestions.append(
                        f"Ensure {field_label} follows the required format"
                    )
                    score_components.append(50.0)
                else:
                    score_components.append(100.0)
            except re.error as e:
                logger.warning(f"Invalid regex pattern for {field_name}: {validation_regex} - {e}")
                score_components.append(100.0)  # Skip if regex is invalid
        
        # Calculate final score for this field
        if not score_components:
            return 100.0, issues, suggestions
        
        final_score = sum(score_components) / len(score_components)
        return round(final_score, 2), issues, suggestions
    
    def get_applicable_rules(self, category: str, content_rules: List[Dict]) -> Dict[str, Dict]:
        """
        Get the applicable rules for a category (merging global and category-specific)
        
        Returns:
            Dict mapping field_name -> rule
        """
        global_rules = [r for r in content_rules if not r.get('category')]
        category_rules = [r for r in content_rules if r.get('category') == category]
        
        merged_rules = {}
        for rule in global_rules:
            merged_rules[rule['field_name']] = rule
        for rule in category_rules:
            merged_rules[rule['field_name']] = rule  # Override global with category-specific
        
        return merged_rules