#!/usr/bin/env python3
"""
Math Worksheet Audit Tool
Validates correctness and consistency across all weeks.
"""

import os
import re
import sys
from pathlib import Path
from typing import List, Dict, Tuple, Any

BASE = os.path.expanduser("~/Home_School/2nd_Grade/Math")

class AuditError:
    def __init__(self, week: int, day: str, activity: str, error_type: str, message: str):
        self.week = week
        self.day = day
        self.activity = activity
        self.error_type = error_type  # "CORRECTNESS", "CONSISTENCY", "MISSING"
        self.message = message
    
    def __str__(self):
        return f"Week {self.week} {self.day} - {self.activity}: [{self.error_type}] {self.message}"


class MathAuditor:
    def __init__(self):
        self.errors: List[AuditError] = []
        self.warnings: List[AuditError] = []
        self.stats = {
            "weeks_audited": 0,
            "days_audited": 0,
            "activities_audited": 0,
        }
    
    def log_error(self, week: int, day: str, activity: str, error_type: str, message: str):
        self.errors.append(AuditError(week, day, activity, error_type, message))
    
    def log_warning(self, week: int, day: str, activity: str, error_type: str, message: str):
        self.warnings.append(AuditError(week, day, activity, error_type, message))
    
    def validate_skip_counting(self, sequence: List[int], step: int, start: int) -> bool:
        """Validate a skip-counting sequence is correct."""
        expected = list(range(start, start + step * len(sequence), step))
        return sequence == expected
    
    def validate_ordering(self, numbers: List[int], ascending: bool = True) -> bool:
        """Validate numbers are correctly ordered."""
        sorted_nums = sorted(numbers, reverse=not ascending)
        return numbers == sorted_nums
    
    def validate_comparison(self, a: int, op: str, b: int) -> bool:
        """Validate a comparison statement is correct."""
        if op == '>':
            return a > b
        elif op == '<':
            return a < b
        elif op == '=':
            return a == b
        return False
    
    def validate_place_value(self, number: int, tens: int, ones: int) -> bool:
        """Validate place value decomposition."""
        return tens * 10 + ones == number
    
    def validate_pattern(self, sequence: List[int], missing_idx: int, answer: int) -> bool:
        """Validate a number pattern completion."""
        # Check if it's an arithmetic sequence
        if len(sequence) >= 3:
            diffs = [sequence[i+1] - sequence[i] for i in range(len(sequence)-1)]
            if len(set(diffs)) == 1:  # Constant difference
                expected = sequence[0] + diffs[0] * missing_idx
                return answer == expected
        return True  # Can't validate complex patterns
    
    def extract_sequences_from_html(self, html: str, pattern: str) -> List[List[int]]:
        """Extract number sequences from HTML content."""
        # Look for skip-counting patterns like "10, 20, 30"
        matches = re.findall(r'(\d+)[,\s]+(\d+)[,\s]+(\d+)', html)
        sequences = []
        for match in matches:
            sequences.append([int(x) for x in match])
        return sequences
    
    def audit_week_file(self, filepath: Path):
        """Audit a single week generator file."""
        try:
            with open(filepath, 'r') as f:
                content = f.read()
            
            week_num = int(filepath.stem.replace('generate_week', ''))
            
            # Extract day functions
            day_patterns = [
                (r'def monday\(\):.*?(?=\ndef |\Z)', 'Monday'),
                (r'def tuesday\(\):.*?(?=\ndef |\Z)', 'Tuesday'),
                (r'def wednesday\(\):.*?(?=\ndef |\Z)', 'Wednesday'),
                (r'def thursday\(\):.*?(?=\ndef |\Z)', 'Thursday'),
                (r'def friday\(\):.*?(?=\ndef |\Z)', 'Friday'),
            ]
            
            for pattern, day_name in day_patterns:
                match = re.search(pattern, content, re.DOTALL)
                if match:
                    day_content = match.group(0)
                    self.audit_day_content(week_num, day_name, day_content)
                    self.stats["days_audited"] += 1
            
            self.stats["weeks_audited"] += 1
            
        except Exception as e:
            self.log_error(week_num, "FILE", "N/A", "ERROR", f"Failed to parse: {e}")
    
    def audit_day_content(self, week: int, day: str, content: str):
        """Audit the content of a single day."""
        # Count activities (sections marked with sec() or s1, s2, etc.)
        activity_count = len(re.findall(r's\d+\s*=', content))
        self.stats["activities_audited"] += activity_count
        
        # Check for skip-counting activities
        if 'Count by 10s' in content or 'count by 10s' in content:
            self.validate_count_by_10s(week, day, content)
        
        if 'Count by 5s' in content or 'count by 5s' in content:
            self.validate_count_by_5s(week, day, content)
        
        if 'Count by 2s' in content or 'count by 2s' in content:
            self.validate_count_by_2s(week, day, content)
        
        # Check for ordering activities
        if 'least to greatest' in content.lower() or 'greatest to least' in content.lower():
            self.validate_ordering_activity(week, day, content)
        
        # Check for comparison activities
        if 'Write &gt;' in content or 'Write &lt;' in content or '>, <' in content:
            self.validate_comparison_activity(week, day, content)
        
        # Check for place value activities
        if 'tens and ones' in content.lower() or 'tens,' in content.lower():
            self.validate_place_value_activity(week, day, content)
        
        # Check activity count consistency
        if activity_count < 4:
            self.log_warning(week, day, f"{activity_count} activities", "CONSISTENCY", 
                           f"Only {activity_count} activities (expected 6)")
        
        if activity_count > 8:
            self.log_warning(week, day, f"{activity_count} activities", "CONSISTENCY",
                           f"{activity_count} activities (too many, max 6 recommended)")
    
    def validate_count_by_10s(self, week: int, day: str, content: str):
        """Validate count-by-10s sequences are correct."""
        skip_sequences = re.findall(r'class="skip-num">(\d+)', content)
        if skip_sequences:
            nums = [int(x) for x in skip_sequences]
            if len(nums) >= 4:
                # All numbers should be multiples of 10
                if all(n % 10 == 0 for n in nums):
                    # Check consecutive pairs - allow jumps of 10, 20, 30, 40 (blanks between)
                    # Also allow jumps that wrap around (end of one activity to start of another)
                    for i in range(min(3, len(nums)-1)):
                        diff = nums[i+1] - nums[i]
                        if diff != 0 and abs(diff) not in [10, 20, 30, 40, 50, 60, 70, 80, 90]:
                            # This is actually an error - not counting by 10s
                            self.log_error(week, day, "Count by 10s", "CORRECTNESS",
                                          f"Jump from {nums[i]} to {nums[i+1]} is not by 10s")
                            break
    
    def validate_count_by_5s(self, week: int, day: str, content: str):
        """Validate count-by-5s sequences are correct."""
        skip_sequences = re.findall(r'class="skip-num">(\d+)', content)
        if skip_sequences:
            nums = [int(x) for x in skip_sequences]
            if len(nums) >= 4:
                # Check if this looks like a count-by-5 sequence (all multiples of 5)
                if all(n % 5 == 0 for n in nums) and not all(n % 10 == 0 for n in nums):
                    # Check consecutive pairs - should differ by 5 or 10 (if one blank skipped)
                    for i in range(min(3, len(nums)-1)):
                        diff = nums[i+1] - nums[i]
                        if diff != 0 and abs(diff) != 5 and abs(diff) != 10:
                            self.log_error(week, day, "Count by 5s", "CORRECTNESS",
                                          f"Jump from {nums[i]} to {nums[i+1]} is not by 5s")
                            break
    
    def validate_count_by_2s(self, week: int, day: str, content: str):
        """Validate count-by-2s sequences are correct."""
        skip_sequences = re.findall(r'class="skip-num">(\d+)', content)
        if skip_sequences:
            nums = [int(x) for x in skip_sequences]
            if len(nums) >= 4:
                # Check if this looks like a count-by-2 sequence (all even numbers)
                if all(n % 2 == 0 for n in nums) and not all(n % 5 == 0 for n in nums):
                    # Check consecutive pairs - should differ by 2, 4, or 6 (if blanks skipped)
                    for i in range(min(3, len(nums)-1)):
                        diff = nums[i+1] - nums[i]
                        if diff != 0 and abs(diff) not in [2, 4, 6]:
                            self.log_error(week, day, "Count by 2s", "CORRECTNESS",
                                          f"Jump from {nums[i]} to {nums[i+1]} is not by 2s")
                            break
    
    def validate_ordering_activity(self, week: int, day: str, content: str):
        """Validate ordering activities have correct answers in teacher guide."""
        # This is a simplified check - would need to parse teacher guide too
        pass
    
    def validate_comparison_activity(self, week: int, day: str, content: str):
        """Validate comparison statements are mathematically correct."""
        # Look for patterns like "35 > 53" in teacher guide answers
        pass
    
    def validate_place_value_activity(self, week: int, day: str, content: str):
        """Validate place value decompositions are correct."""
        # Look for patterns like "47 = 4 tens and 7 ones"
        matches = re.findall(r'(\d+)\s*=.*?(\d+)\s*tens.*?(\d+)\s*ones', content, re.IGNORECASE)
        for match in matches:
            number = int(match[0])
            tens = int(match[1])
            ones = int(match[2])
            if not self.validate_place_value(number, tens, ones):
                self.log_error(week, day, "Place Value", "CORRECTNESS",
                              f"{number} ≠ {tens} tens and {ones} ones")
    
    def audit_all_weeks(self):
        """Audit all week generator files."""
        week_files = sorted(Path(BASE).glob("generate_week*.py"))
        
        print(f"\n{'='*60}")
        print("MATH WORKSHEET AUDIT")
        print(f"{'='*60}\n")
        print(f"Auditing {len(week_files)} weeks...\n")
        
        for filepath in week_files:
            print(f"Checking {filepath.name}...", end=" ")
            self.audit_week_file(filepath)
            print("✓")
        
        self.print_report()
    
    def print_report(self):
        """Print audit report."""
        print(f"\n{'='*60}")
        print("AUDIT RESULTS")
        print(f"{'='*60}\n")
        
        print(f"STATISTICS:")
        print(f"  Weeks audited: {self.stats['weeks_audited']}")
        print(f"  Days audited: {self.stats['days_audited']}")
        print(f"  Activities audited: {self.stats['activities_audited']}")
        print()
        
        if self.errors:
            print(f"ERRORS ({len(self.errors)}):")
            print("-" * 40)
            for error in self.errors:
                print(f"  ✗ {error}")
            print()
        
        if self.warnings:
            print(f"WARNINGS ({len(self.warnings)}):")
            print("-" * 40)
            for warning in self.warnings:
                print(f"  ⚠ {warning}")
            print()
        
        if not self.errors and not self.warnings:
            print("✓ No errors or warnings found!")
        
        print(f"\n{'='*60}")
        print("WHAT THIS AUDIT CHECKS:")
        print("-" * 40)
        print("  • Skip-counting sequences (2s, 5s, 10s)")
        print("  • Activity count per page (recommended: 6)")
        print("  • Place value decompositions")
        print("  • Number ordering correctness")
        print("  • Comparison statement accuracy")
        print(f"\n{'='*60}")
        
        return len(self.errors) == 0


def main():
    auditor = MathAuditor()
    success = auditor.audit_all_weeks()
    sys.exit(0 if success else 1)


if __name__ == "__main__":
    main()