#!/usr/bin/env python3
"""Audit all ELA week generators for quality issues.

Checks:
  1. Word swap challenges where swap words = original words (no cognitive gain)
  2. Story quality indicators (forced word cramming, nonsensical sentences)
  3. Duplicate if __name__ blocks (syntax error risk)
  4. Indentation errors
  5. Swap data where grammatical roles don't match
  6. Story text that's too short or too long
"""

import ast
import os
import re
import sys
from pathlib import Path

ELA_ROOT = Path(os.path.expanduser("~/Home_School/2nd_Grade/English_Language_Arts"))
ISSUES = {}  # file -> list of (line, severity, message)

def scan_file(filepath):
    """Scan a single generator file for quality issues."""
    issues = []
    rel = filepath.relative_to(ELA_ROOT)
    
    try:
        source = filepath.read_text()
    except Exception as e:
        issues.append((0, "ERROR", f"Cannot read file: {e}"))
        return issues
    
    # Check 1: Duplicate if __name__ blocks
    name_main_count = source.count('if __name__ == "__main__":')
    if name_main_count > 1:
        issues.append((0, "HIGH", f"Duplicate if __name__ == '__main__' blocks ({name_main_count} found)"))
    
    # Check 2: Try to parse as Python to catch syntax errors
    try:
        tree = ast.parse(source)
    except SyntaxError as e:
        issues.append((e.lineno or 0, "HIGH", f"Syntax error: {e.msg} (line {e.lineno})"))
        # Can't do deeper analysis without valid AST
        return issues
    
    # Check 3: Story text analysis
    for node in ast.walk(tree):
        if isinstance(node, ast.Constant) and isinstance(node.value, str):
            text = node.value
            # Look for story-like text (long strings with HTML)
            if len(text) > 100 and '<strong>' in text:
                # Check for forced word cramming indicators
                words_in_story = re.findall(r'<strong>(\w+)</strong>', text)
                plain_words = re.findall(r'\b(\w+)\b', text.replace('<', '').replace('>', ''))
                
                # Story too short (< 50 words)
                if len(plain_words) < 50 and len(words_in_story) > 3:
                    issues.append((node.lineno, "MEDIUM", f"Story at line {node.lineno} has only {len(plain_words)} words - may be too brief"))
                
                # Story too long (> 400 words)
                if len(plain_words) > 400:
                    issues.append((node.lineno, "LOW", f"Story at line {node.lineno} has {len(plain_words)} words - may be too long for grade level"))
                
                # Check for nonsensical word combinations
                # Look for "insect" with wrong articles ("a insect" instead of "an insect")
                if re.search(r'\b[aA]\s+insect\b', text):
                    issues.append((node.lineno, "MEDIUM", f"Story at line {node.lineno}: 'a insect' should be 'an insect'"))
                
                # Check for "octopus" with wrong articles
                if re.search(r'\b[aA]\s+octopus\b', text):
                    issues.append((node.lineno, "MEDIUM", f"Story at line {node.lineno}: 'a octopus' should be 'an octopus'"))
                
                # Check for forced/nonsensical combinations
                if re.search(r'\b(bubble|insect|helmet|kitten)\s+(bubble|insect|helmet|kitten)\b', text):
                    issues.append((node.lineno, "MEDIUM", f"Story at line {node.lineno}: possible repetitive word usage"))
    
    # Check 4: Word swap challenge analysis
    for node in ast.walk(tree):
        if isinstance(node, ast.List):
            # Look for swap_data lists
            if hasattr(node, 'ctx'):
                # Find assignment target
                for parent in ast.walk(tree):
                    if isinstance(parent, ast.Assign) and isinstance(parent.targets[0], ast.Name) and 'swap' in parent.targets[0].id.lower():
                        if parent.value == node or (isinstance(parent.value, ast.ListComp) or isinstance(parent.value, ast.List)):
                            # Check swap data
                            for item in node.elts:
                                if isinstance(item, ast.Tuple):
                                    # Try to evaluate the swap data
                                    try:
                                        if len(item.elts) >= 3:
                                            # First element should be sentence, others should be tuples
                                            sentence_node = item.elts[0]
                                            if isinstance(sentence_node, ast.Constant) and isinstance(sentence_node.value, str):
                                                sentence = sentence_node.value
                                                # Extract words from sentence
                                                sentence_words = set(re.findall(r'\b(\w+)\b', sentence.replace('<', '').replace('>', '')))
                                                
                                                # Check swap words
                                                for swap_tuple in item.elts[1:]:
                                                    if isinstance(swap_tuple, ast.Tuple) and len(swap_tuple.elts) >= 2:
                                                        orig_word = swap_tuple.elts[0].value if isinstance(swap_tuple.elts[0], ast.Constant) else None
                                                        new_word = swap_tuple.elts[1].value if isinstance(swap_tuple.elts[1], ast.Constant) else None
                                                        
                                                        if orig_word and new_word:
                                                            # Check if swap words are the same as original
                                                            if orig_word.lower() == new_word.lower():
                                                                issues.append((item.lineno, "HIGH", f"Word swap uses same word: '{orig_word}' -> '{new_word}' (no change)"))
                                                            elif orig_word.lower() not in sentence_words:
                                                                issues.append((item.lineno, "MEDIUM", f"Word swap: '{orig_word}' not found in sentence"))
                                                            elif new_word.lower() in sentence_words:
                                                                issues.append((item.lineno, "MEDIUM", f"Word swap: '{new_word}' already appears in sentence"))
                                    except (AttributeError, IndexError, TypeError):
                                        pass
    
    return issues

def main():
    print("Auditing ELA generators...\n")
    
    # Find all week generators
    generators = []
    for week_dir in sorted(ELA_ROOT.glob("Week_*")):
        gen_file = week_dir / "generate_week*.py"
        for f in gen_file.glob("*.py"):
            if "generate" in f.name.lower():
                generators.append(f)
    
    # Also check shared day templates
    shared = [
        "tuesday.py", "wednesday.py", "thursday.py", "friday.py", "monday.py",
        "tuesday_wp.py", "wednesday_wp.py", "thursday_wp.py", "friday_wp.py", "monday_wp.py"
    ]
    for s in shared:
        f = ELA_ROOT / s
        if f.exists():
            generators.append(f)
    
    print(f"Found {len(generators)} files to audit\n")
    print("=" * 80)
    
    for filepath in generators:
        file_issues = scan_file(filepath)
        if file_issues:
            rel = filepath.relative_to(ELA_ROOT)
            print(f"\n{rel}:")
            for line, severity, msg in file_issues:
                marker = "🔴" if severity == "HIGH" else "🟡" if severity == "MEDIUM" else "🔵"
                print(f"  {marker} Line {line}: {msg}")
    
    print("\n" + "=" * 80)
    print("Audit complete.")

if __name__ == "__main__":
    main()
