"""
Input validation schemas using basic validation
For production, consider migrating to Pydantic for comprehensive validation
"""

import re
import bleach
from functools import wraps
from flask import request, jsonify

class ValidationError(Exception):
    """Custom validation error"""
    pass

def sanitize_html(text):
    """
    Sanitize HTML to prevent XSS attacks
    Allows only safe tags and attributes
    """
    if not text:
        return text
    
    # Allow minimal formatting tags
    allowed_tags = ['p', 'br', 'strong', 'em', 'u', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li', 'ul', 'ol', 'pre', 'code']
    allowed_attributes = {}
    
    return bleach.clean(
        text,
        tags=allowed_tags,
        attributes=allowed_attributes,
        strip=True
    )

def validate_string(value, field_name, min_length=None, max_length=None, pattern=None, required=True):
    """Validate string field"""
    if value is None or value == '':
        if required:
            raise ValidationError(f"{field_name} is required")
        return True
    
    if not isinstance(value, str):
        raise ValidationError(f"{field_name} must be a string")
    
    if min_length and len(value) < min_length:
        raise ValidationError(f"{field_name} must be at least {min_length} characters")
    
    if max_length and len(value) > max_length:
        raise ValidationError(f"{field_name} must not exceed {max_length} characters")
    
    if pattern and not re.match(pattern, value):
        raise ValidationError(f"{field_name} has invalid format")
    
    return True

def validate_email(email, required=False):
    """Validate email format"""
    if not email and not required:
        return True
    
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    if not re.match(pattern, email):
        raise ValidationError("Invalid email format")
    return True

def sanitize_filename(filename):
    """Sanitize filename to prevent path traversal"""
    # Remove any path separators
    filename = filename.replace('..', '').replace('/', '').replace('\\', '')
    # Allow only alphanumeric, dash, underscore, and dot
    filename = re.sub(r'[^a-zA-Z0-9._-]', '_', filename)
    return filename[:255]  # Limit length

def validate_uuid(value):
    """Validate UUID format"""
    uuid_pattern = r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
    if not re.match(uuid_pattern, str(value).lower()):
        raise ValidationError("Invalid UUID format")
    return True

# Request validation schemas
PROFILE_SCHEMA = {
    'name': {'type': 'string', 'required': True, 'min_length': 1, 'max_length': 255},
    'email': {'type': 'email', 'required': False},
    'contact_number': {'type': 'string', 'required': False, 'max_length': 50},
    'default_key': {'type': 'string', 'required': False, 'max_length': 10},
    'notes': {'type': 'string', 'required': False, 'max_length': 5000}
}

SONG_SCHEMA = {
    'title': {'type': 'string', 'required': True, 'min_length': 1, 'max_length': 500},
    'artist': {'type': 'string', 'required': False, 'max_length': 500},
    'band': {'type': 'string', 'required': False, 'max_length': 500},
    'singer': {'type': 'string', 'required': False, 'max_length': 500},
    'lyrics': {'type': 'string', 'required': False, 'max_length': 50000},
    'chords': {'type': 'string', 'required': False, 'max_length': 50000}
}

PLAN_SCHEMA = {
    'name': {'type': 'string', 'required': True, 'min_length': 1, 'max_length': 500},
    'date': {'type': 'string', 'required': False},  # Will validate format separately
    'notes': {'type': 'string', 'required': False, 'max_length': 5000}
}

def validate_request_data(schema):
    """
    Decorator to validate request JSON data against schema
    
    Usage:
        @app.route('/api/profiles', methods=['POST'])
        @validate_request_data(PROFILE_SCHEMA)
        def create_profile():
            data = request.get_json()
            ...
    """
    def decorator(f):
        @wraps(f)
        def wrapped(*args, **kwargs):
            if not request.is_json:
                return jsonify({'error': 'Content-Type must be application/json'}), 400
            
            data = request.get_json()
            if not data:
                return jsonify({'error': 'Request body is required'}), 400
            
            try:
                # Validate each field in schema
                for field, rules in schema.items():
                    value = data.get(field)
                    
                    if rules['type'] == 'string':
                        validate_string(
                            value,
                            field,
                            min_length=rules.get('min_length'),
                            max_length=rules.get('max_length'),
                            pattern=rules.get('pattern'),
                            required=rules.get('required', False)
                        )
                    elif rules['type'] == 'email':
                        if value:
                            validate_email(value, required=rules.get('required', False))
                
                return f(*args, **kwargs)
            
            except ValidationError as e:
                return jsonify({'error': 'validation_error', 'message': str(e)}), 400
        
        return wrapped
    return decorator
