"""
Example Validation Test Harness

Validates examples.csv for schema compliance, code completeness, and quality.
"""

import csv
import json
from pathlib import Path
from typing import List, Dict, Any, Tuple


# Required fields in examples.csv
REQUIRED_FIELDS = [
    'id', 'domain', 'example_type', 'scenario', 'problem',
    'solution_code', 'explanation', 'test_inputs', 'expected_outputs',
    'tags', 'difficulty'
]

# Valid enum values
VALID_EXAMPLE_TYPES = ['quickstart', 'integration', 'debugging', 'best-practice', 'security']
VALID_DIFFICULTIES = ['beginner', 'intermediate', 'advanced']
VALID_DOMAINS = [
    'defi', 'nfts', 'tokens', 'security', 'auth', 'bns',
    'stacking', 'oracles', 'advanced', 'chainhooks', 'trading',
    'clarity', 'deployment', 'templates'
]


class ValidationError:
    """Represents a validation error"""
    def __init__(self, example_id: str, field: str, message: str, severity: str = 'error'):
        self.example_id = example_id
        self.field = field
        self.message = message
        self.severity = severity  # 'error', 'warning', 'info'

    def __repr__(self):
        symbol = '❌' if self.severity == 'error' else '⚠️' if self.severity == 'warning' else 'ℹ️'
        return f"{symbol} Example {self.example_id} - {self.field}: {self.message}"


def validate_schema(example: Dict[str, Any]) -> List[ValidationError]:
    """
    Validate example has all required fields

    Args:
        example: Example dictionary from CSV

    Returns:
        List of validation errors
    """
    errors = []

    # Check required fields
    for field in REQUIRED_FIELDS:
        if not example.get(field):
            errors.append(ValidationError(
                example.get('id', 'unknown'),
                field,
                f"Missing required field: {field}"
            ))

    return errors


def validate_enums(example: Dict[str, Any]) -> List[ValidationError]:
    """
    Validate enum fields have valid values

    Args:
        example: Example dictionary from CSV

    Returns:
        List of validation errors
    """
    errors = []
    example_id = example.get('id', 'unknown')

    # Validate example_type
    if example.get('example_type') not in VALID_EXAMPLE_TYPES:
        errors.append(ValidationError(
            example_id,
            'example_type',
            f"Invalid example_type: {example.get('example_type')}. Must be one of {VALID_EXAMPLE_TYPES}"
        ))

    # Validate difficulty
    if example.get('difficulty') not in VALID_DIFFICULTIES:
        errors.append(ValidationError(
            example_id,
            'difficulty',
            f"Invalid difficulty: {example.get('difficulty')}. Must be one of {VALID_DIFFICULTIES}"
        ))

    # Validate domain
    if example.get('domain') not in VALID_DOMAINS:
        errors.append(ValidationError(
            example_id,
            'domain',
            f"Invalid domain: {example.get('domain')}. Must be one of {VALID_DOMAINS}",
            severity='warning'
        ))

    return errors


def validate_json_fields(example: Dict[str, Any]) -> List[ValidationError]:
    """
    Validate JSON fields are valid JSON

    Args:
        example: Example dictionary from CSV

    Returns:
        List of validation errors
    """
    errors = []
    example_id = example.get('id', 'unknown')

    # Validate test_inputs
    if example.get('test_inputs'):
        try:
            json.loads(example['test_inputs'])
        except json.JSONDecodeError as e:
            errors.append(ValidationError(
                example_id,
                'test_inputs',
                f"Invalid JSON in test_inputs: {str(e)}"
            ))

    # Validate expected_outputs
    if example.get('expected_outputs'):
        try:
            json.loads(example['expected_outputs'])
        except json.JSONDecodeError as e:
            errors.append(ValidationError(
                example_id,
                'expected_outputs',
                f"Invalid JSON in expected_outputs: {str(e)}"
            ))

    return errors


def validate_code_completeness(example: Dict[str, Any]) -> List[ValidationError]:
    """
    Validate code appears complete with imports and reasonable length

    Args:
        example: Example dictionary from CSV

    Returns:
        List of validation errors
    """
    errors = []
    example_id = example.get('id', 'unknown')
    code = example.get('solution_code', '')

    # Check for imports (JavaScript/TypeScript)
    has_import = any(keyword in code for keyword in ['import ', 'require(', 'from '])

    if not has_import and len(code) > 100:
        errors.append(ValidationError(
            example_id,
            'solution_code',
            "Code appears to be missing import statements",
            severity='warning'
        ))

    # Check minimum length (complete examples should be substantial)
    if len(code) < 200:
        errors.append(ValidationError(
            example_id,
            'solution_code',
            f"Code seems too short ({len(code)} chars). Complete examples should be > 200 chars.",
            severity='warning'
        ))

    # Check for common patterns that indicate completeness
    if 'import' in code and 'function' not in code and 'const' not in code and 'await' not in code:
        errors.append(ValidationError(
            example_id,
            'solution_code',
            "Code has imports but no actual implementation",
            severity='warning'
        ))

    return errors


def validate_quality(example: Dict[str, Any]) -> List[ValidationError]:
    """
    Validate example quality (pitfalls, explanations, etc.)

    Args:
        example: Example dictionary from CSV

    Returns:
        List of validation errors
    """
    errors = []
    example_id = example.get('id', 'unknown')

    # Check pitfalls exist
    pitfalls = example.get('pitfalls', '')
    if not pitfalls:
        errors.append(ValidationError(
            example_id,
            'pitfalls',
            "Missing common pitfalls. Examples should document common mistakes.",
            severity='warning'
        ))
    elif len(pitfalls) < 50:
        errors.append(ValidationError(
            example_id,
            'pitfalls',
            "Pitfalls seem too brief. Include 3-5 common mistakes.",
            severity='info'
        ))

    # Check explanation exists and is substantial
    explanation = example.get('explanation', '')
    if not explanation:
        errors.append(ValidationError(
            example_id,
            'explanation',
            "Missing explanation. Examples should explain how the solution works.",
            severity='warning'
        ))
    elif len(explanation) < 50:
        errors.append(ValidationError(
            example_id,
            'explanation',
            "Explanation seems too brief. Provide step-by-step breakdown.",
            severity='info'
        ))

    # Check tags exist
    tags = example.get('tags', '')
    if not tags:
        errors.append(ValidationError(
            example_id,
            'tags',
            "Missing tags. Add relevant keywords for search.",
            severity='info'
        ))

    # Check for live example URL (best practice, not required)
    if not example.get('live_example_url'):
        errors.append(ValidationError(
            example_id,
            'live_example_url',
            "No live example URL. Consider linking to production code.",
            severity='info'
        ))

    return errors


def validate_related_snippets(example: Dict[str, Any]) -> List[ValidationError]:
    """
    Validate related_snippets format

    Args:
        example: Example dictionary from CSV

    Returns:
        List of validation errors
    """
    errors = []
    example_id = example.get('id', 'unknown')
    related = example.get('related_snippets', '')

    if related:
        # Format should be: "file.csv:id,file2.csv:id2"
        refs = related.split(',')
        for ref in refs:
            ref = ref.strip()
            if ':' not in ref:
                errors.append(ValidationError(
                    example_id,
                    'related_snippets',
                    f"Invalid format in related_snippets: '{ref}'. Expected format: 'file.csv:id'",
                    severity='error'
                ))
            elif not ref.endswith('.csv'):
                parts = ref.split(':')
                if len(parts) >= 1 and not parts[0].endswith('.csv'):
                    errors.append(ValidationError(
                        example_id,
                        'related_snippets',
                        f"File must end with .csv: '{ref}'",
                        severity='warning'
                    ))

    return errors


def validate_example(example: Dict[str, Any]) -> List[ValidationError]:
    """
    Run all validation checks on an example

    Args:
        example: Example dictionary from CSV

    Returns:
        List of all validation errors
    """
    errors = []

    errors.extend(validate_schema(example))
    errors.extend(validate_enums(example))
    errors.extend(validate_json_fields(example))
    errors.extend(validate_code_completeness(example))
    errors.extend(validate_quality(example))
    errors.extend(validate_related_snippets(example))

    return errors


def validate_all_examples(csv_path: Path = None) -> Tuple[int, int, int, List[ValidationError]]:
    """
    Validate all examples in examples.csv

    Args:
        csv_path: Path to examples.csv. If None, uses default location.

    Returns:
        Tuple of (num_examples, num_errors, num_warnings, all_errors)
    """
    if csv_path is None:
        script_dir = Path(__file__).parent
        csv_path = script_dir.parent / 'data' / 'examples.csv'

    if not csv_path.exists():
        print(f"❌ examples.csv not found at: {csv_path}")
        return 0, 1, 0, []

    all_errors = []
    num_examples = 0

    with open(csv_path, 'r', encoding='utf-8') as f:
        reader = csv.DictReader(f)
        examples = list(reader)
        num_examples = len(examples)

    for example in examples:
        errors = validate_example(example)
        all_errors.extend(errors)

    # Count errors vs warnings
    num_errors = len([e for e in all_errors if e.severity == 'error'])
    num_warnings = len([e for e in all_errors if e.severity == 'warning'])

    return num_examples, num_errors, num_warnings, all_errors


def print_validation_report(csv_path: Path = None):
    """
    Print a comprehensive validation report

    Args:
        csv_path: Path to examples.csv
    """
    print("=" * 80)
    print("EXAMPLE VALIDATION REPORT")
    print("=" * 80)

    num_examples, num_errors, num_warnings, all_errors = validate_all_examples(csv_path)

    if num_examples == 0:
        print("\n❌ No examples found to validate")
        return

    print(f"\nTotal examples validated: {num_examples}")
    print(f"Errors: {num_errors}")
    print(f"Warnings: {num_warnings}")
    print(f"Info: {len([e for e in all_errors if e.severity == 'info'])}")

    if all_errors:
        print("\n" + "=" * 80)
        print("VALIDATION ISSUES")
        print("=" * 80)

        # Group by example ID
        by_example = {}
        for error in all_errors:
            if error.example_id not in by_example:
                by_example[error.example_id] = []
            by_example[error.example_id].append(error)

        for example_id, errors in sorted(by_example.items()):
            print(f"\nExample {example_id}:")
            for error in errors:
                print(f"  {error}")

    print("\n" + "=" * 80)

    if num_errors == 0:
        print("✅ ALL EXAMPLES PASS VALIDATION (no errors)")
    else:
        print(f"❌ VALIDATION FAILED - {num_errors} error(s) found")

    if num_warnings > 0:
        print(f"⚠️  {num_warnings} warning(s) - review recommended")

    print("=" * 80)

    return num_errors == 0


if __name__ == '__main__':
    import sys

    csv_path = None
    if len(sys.argv) > 1:
        csv_path = Path(sys.argv[1])

    success = print_validation_report(csv_path)
    sys.exit(0 if success else 1)
