from flask import Blueprint, request, jsonify
from src.models.database import db
from src.models.recognition import Recognition
from src.models.camera import Camera
from datetime import datetime
from sqlalchemy import func, desc, and_, or_

search_bp = Blueprint('search', __name__)

@search_bp.route('/recognitions', methods=['GET'])
def search_recognitions():
    """Search recognitions with various filters"""
    # Get filter parameters
    license_plate = request.args.get('license_plate')
    camera_id = request.args.get('camera_id')
    date_from = request.args.get('date_from')
    date_to = request.args.get('date_to')
    confidence_min = request.args.get('confidence_min', type=float)
    confidence_max = request.args.get('confidence_max', type=float)
    is_in_whitelist = request.args.get('is_in_whitelist')
    is_in_blacklist = request.args.get('is_in_blacklist')
    processed = request.args.get('processed')
    
    # Pagination parameters
    page = request.args.get('page', 1, type=int)
    per_page = request.args.get('per_page', 20, type=int)
    
    # Build query
    query = db.session.query(Recognition, Camera).join(
        Camera, Recognition.camera_id == Camera.id
    )
    
    # Apply filters
    if license_plate:
        query = query.filter(Recognition.license_plate.like(f'%{license_plate}%'))
    
    if camera_id:
        query = query.filter(Recognition.camera_id == camera_id)
    
    if date_from:
        try:
            date_from = datetime.fromisoformat(date_from)
            query = query.filter(Recognition.capture_time >= date_from)
        except ValueError:
            return jsonify({'error': 'Invalid date_from format. Use ISO format (YYYY-MM-DDTHH:MM:SS)'}), 400
    
    if date_to:
        try:
            date_to = datetime.fromisoformat(date_to)
            query = query.filter(Recognition.capture_time <= date_to)
        except ValueError:
            return jsonify({'error': 'Invalid date_to format. Use ISO format (YYYY-MM-DDTHH:MM:SS)'}), 400
    
    if confidence_min is not None:
        query = query.filter(Recognition.confidence >= confidence_min)
    
    if confidence_max is not None:
        query = query.filter(Recognition.confidence <= confidence_max)
    
    if is_in_whitelist is not None:
        is_in_whitelist = is_in_whitelist.lower() == 'true'
        query = query.filter(Recognition.is_in_whitelist == is_in_whitelist)
    
    if is_in_blacklist is not None:
        is_in_blacklist = is_in_blacklist.lower() == 'true'
        query = query.filter(Recognition.is_in_blacklist == is_in_blacklist)
    
    if processed is not None:
        processed = processed.lower() == 'true'
        query = query.filter(Recognition.processed == processed)
    
    # Order by capture time (newest first)
    query = query.order_by(Recognition.capture_time.desc())
    
    # Paginate results
    total = query.count()
    query = query.limit(per_page).offset((page - 1) * per_page)
    
    # Format results
    results = []
    for recognition, camera in query.all():
        recognition_dict = recognition.to_dict()
        recognition_dict['camera_name'] = camera.name
        recognition_dict['camera_location'] = camera.location
        results.append(recognition_dict)
    
    return jsonify({
        'recognitions': results,
        'total': total,
        'page': page,
        'per_page': per_page,
        'pages': (total + per_page - 1) // per_page
    }), 200

@search_bp.route('/recognitions/<int:recognition_id>', methods=['GET'])
def get_recognition(recognition_id):
    """Get a specific recognition by ID"""
    recognition = Recognition.query.get_or_404(recognition_id)
    
    # Get camera details
    camera = Camera.query.get(recognition.camera_id)
    
    recognition_dict = recognition.to_dict()
    if camera:
        recognition_dict['camera_name'] = camera.name
        recognition_dict['camera_location'] = camera.location
    
    return jsonify(recognition_dict), 200

@search_bp.route('/recognitions/<int:recognition_id>', methods=['PUT'])
def update_recognition(recognition_id):
    """Update a recognition (e.g., correct license plate)"""
    recognition = Recognition.query.get_or_404(recognition_id)
    data = request.json
    
    if 'license_plate' in data:
        recognition.license_plate = data.get('license_plate')
    
    if 'is_in_whitelist' in data:
        recognition.is_in_whitelist = data.get('is_in_whitelist')
    
    if 'is_in_blacklist' in data:
        recognition.is_in_blacklist = data.get('is_in_blacklist')
    
    if 'processed' in data:
        recognition.processed = data.get('processed')
    
    db.session.commit()
    
    return jsonify(recognition.to_dict()), 200

@search_bp.route('/history/<string:license_plate>', methods=['GET'])
def get_recognition_history(license_plate):
    """Get recognition history for a specific license plate"""
    limit = request.args.get('limit', 20, type=int)
    
    query = db.session.query(Recognition, Camera).join(
        Camera, Recognition.camera_id == Camera.id
    ).filter(Recognition.license_plate == license_plate)
    
    query = query.order_by(Recognition.capture_time.desc()).limit(limit)
    
    results = []
    for recognition, camera in query.all():
        recognition_dict = recognition.to_dict()
        recognition_dict['camera_name'] = camera.name
        recognition_dict['camera_location'] = camera.location
        results.append(recognition_dict)
    
    return jsonify(results), 200

@search_bp.route('/stats/camera', methods=['GET'])
def get_recognition_stats_by_camera():
    """Get recognition statistics by camera"""
    date_from = request.args.get('date_from')
    date_to = request.args.get('date_to')
    
    # Build query
    query = db.session.query(
        Camera.id,
        Camera.name,
        Camera.location,
        func.count(Recognition.id).label('recognition_count'),
        func.sum(Recognition.is_in_whitelist.cast(db.Integer)).label('whitelist_count'),
        func.sum(Recognition.is_in_blacklist.cast(db.Integer)).label('blacklist_count')
    ).join(
        Recognition, Camera.id == Recognition.camera_id
    ).group_by(
        Camera.id, Camera.name, Camera.location
    )
    
    # Apply date filters
    if date_from:
        try:
            date_from = datetime.fromisoformat(date_from)
            query = query.filter(Recognition.capture_time >= date_from)
        except ValueError:
            return jsonify({'error': 'Invalid date_from format. Use ISO format (YYYY-MM-DDTHH:MM:SS)'}), 400
    
    if date_to:
        try:
            date_to = datetime.fromisoformat(date_to)
            query = query.filter(Recognition.capture_time <= date_to)
        except ValueError:
            return jsonify({'error': 'Invalid date_to format. Use ISO format (YYYY-MM-DDTHH:MM:SS)'}), 400
    
    # Order by recognition count (highest first)
    query = query.order_by(desc('recognition_count'))
    
    # Format results
    results = []
    for row in query.all():
        results.append({
            'id': row.id,
            'name': row.name,
            'location': row.location,
            'recognition_count': row.recognition_count,
            'whitelist_count': row.whitelist_count or 0,
            'blacklist_count': row.blacklist_count or 0
        })
    
    return jsonify(results), 200

@search_bp.route('/stats/day', methods=['GET'])
def get_recognition_stats_by_day():
    """Get recognition statistics by day"""
    date_from = request.args.get('date_from')
    date_to = request.args.get('date_to')
    
    # Build query
    query = db.session.query(
        func.date(Recognition.capture_time).label('date'),
        func.count(Recognition.id).label('recognition_count'),
        func.sum(Recognition.is_in_whitelist.cast(db.Integer)).label('whitelist_count'),
        func.sum(Recognition.is_in_blacklist.cast(db.Integer)).label('blacklist_count')
    ).group_by(
        func.date(Recognition.capture_time)
    )
    
    # Apply date filters
    if date_from:
        try:
            date_from = datetime.fromisoformat(date_from)
            query = query.filter(Recognition.capture_time >= date_from)
        except ValueError:
            return jsonify({'error': 'Invalid date_from format. Use ISO format (YYYY-MM-DDTHH:MM:SS)'}), 400
    
    if date_to:
        try:
            date_to = datetime.fromisoformat(date_to)
            query = query.filter(Recognition.capture_time <= date_to)
        except ValueError:
            return jsonify({'error': 'Invalid date_to format. Use ISO format (YYYY-MM-DDTHH:MM:SS)'}), 400
    
    # Order by date (newest first)
    query = query.order_by(desc('date'))
    
    # Format results
    results = []
    for row in query.all():
        results.append({
            'date': row.date.isoformat(),
            'recognition_count': row.recognition_count,
            'whitelist_count': row.whitelist_count or 0,
            'blacklist_count': row.blacklist_count or 0
        })
    
    return jsonify(results), 200

@search_bp.route('/stats/hour', methods=['GET'])
def get_recognition_stats_by_hour():
    """Get recognition statistics by hour"""
    date = request.args.get('date')
    
    # Build query
    query = db.session.query(
        func.extract('hour', Recognition.capture_time).label('hour'),
        func.count(Recognition.id).label('recognition_count'),
        func.sum(Recognition.is_in_whitelist.cast(db.Integer)).label('whitelist_count'),
        func.sum(Recognition.is_in_blacklist.cast(db.Integer)).label('blacklist_count')
    )
    
    # Apply date filter
    if date:
        try:
            date_obj = datetime.fromisoformat(date.split('T')[0])
            next_day = datetime(date_obj.year, date_obj.month, date_obj.day) + datetime.timedelta(days=1)
            query = query.filter(
                Recognition.capture_time >= date_obj,
                Recognition.capture_time < next_day
            )
        except ValueError:
            return jsonify({'error': 'Invalid date format. Use ISO format (YYYY-MM-DD)'}), 400
    
    # Group by hour
    query = query.group_by('hour').order_by('hour')
    
    # Format results
    results = []
    for row in query.all():
        results.append({
            'hour': int(row.hour),
            'recognition_count': row.recognition_count,
            'whitelist_count': row.whitelist_count or 0,
            'blacklist_count': row.blacklist_count or 0
        })
    
    return jsonify(results), 200

@search_bp.route('/recognitions', methods=['POST'])
def add_recognition():
    """Add a new recognition (from camera processing)"""
    data = request.json
    
    if not data or not data.get('license_plate') or not data.get('camera_id'):
        return jsonify({'error': 'License plate and camera ID are required'}), 400
    
    # Check if camera exists
    camera = Camera.query.get(data.get('camera_id'))
    if not camera:
        return jsonify({'error': 'Camera not found'}), 404
    
    # Check whitelist and blacklist
    from src.models.list import Whitelist, Blacklist
    
    is_in_whitelist = False
    is_in_blacklist = False
    
    whitelist_entry = Whitelist.query.filter_by(license_plate=data.get('license_plate')).first()
    if whitelist_entry and whitelist_entry.is_valid:
        is_in_whitelist = True
    
    blacklist_entry = Blacklist.query.filter_by(license_plate=data.get('license_plate')).first()
    if blacklist_entry and blacklist_entry.is_valid:
        is_in_blacklist = True
    
    # Create recognition
    recognition = Recognition(
        license_plate=data.get('license_plate'),
        camera_id=data.get('camera_id'),
        stream_id=data.get('stream_id'),
        capture_time=datetime.fromisoformat(data.get('capture_time')) if data.get('capture_time') else datetime.utcnow(),
        confidence=data.get('confidence'),
        image_path=data.get('image_path'),
        is_in_whitelist=is_in_whitelist,
        is_in_blacklist=is_in_blacklist,
        processed=False
    )
    
    db.session.add(recognition)
    db.session.commit()
    
    # Create blacklist alert if needed
    if is_in_blacklist:
        from src.routes.notification import create_blacklist_alert
        create_blacklist_alert({
            'license_plate': data.get('license_plate'),
            'recognition_id': recognition.id,
            'camera_id': data.get('camera_id')
        })
    
    return jsonify(recognition.to_dict()), 201
