from flask import request, jsonify
from app import db
from app.api import bp
from app.models import Printer, PrintJob
from app.auth.routes import token_required, admin_required
from datetime import datetime

@bp.route('/printers', methods=['GET'])
def get_printers():
    """Get all printers"""
    printers = Printer.query.all()
    result = []
    
    for printer in printers:
        # Get active job for the printer if any
        now = datetime.utcnow()
        active_job = PrintJob.query.filter_by(printer_id=printer.id, aborted=False) \
            .filter(PrintJob.start_at <= now) \
            .filter(PrintJob.start_at.op('+')(PrintJob.duration_in_minutes * 60) > now) \
            .first()
        
        printer_data = {
            'id': printer.id,
            'name': printer.name,
            'description': printer.description,
            'status': printer.status,
            'is_available': printer.status == 0 and active_job is None,
            'active_job': active_job.to_dict() if active_job else None
        }
        result.append(printer_data)
    
    return jsonify(result)

@bp.route('/printers/<printer_id>', methods=['GET'])
def get_printer(printer_id):
    """Get a specific printer"""
    printer = Printer.query.get_or_404(printer_id)
    
    # Get active job for the printer if any
    now = datetime.utcnow()
    active_job = PrintJob.query.filter_by(printer_id=printer.id, aborted=False) \
        .filter(PrintJob.start_at <= now) \
        .filter(PrintJob.start_at.op('+')(PrintJob.duration_in_minutes * 60) > now) \
        .first()
    
    # Get upcoming jobs
    upcoming_jobs = PrintJob.query.filter_by(printer_id=printer.id, aborted=False) \
        .filter(PrintJob.start_at > now) \
        .order_by(PrintJob.start_at) \
        .limit(5) \
        .all()
    
    result = {
        'id': printer.id,
        'name': printer.name,
        'description': printer.description,
        'status': printer.status,
        'is_available': printer.status == 0 and active_job is None,
        'active_job': active_job.to_dict() if active_job else None,
        'upcoming_jobs': [job.to_dict() for job in upcoming_jobs]
    }
    
    return jsonify(result)

@bp.route('/printers', methods=['POST'])
@admin_required
def create_printer():
    """Create a new printer (admin only)"""
    data = request.get_json() or {}
    
    required_fields = ['name', 'description']
    for field in required_fields:
        if field not in data:
            return jsonify({'error': f'Missing required field: {field}'}), 400
    
    printer = Printer(
        name=data['name'],
        description=data['description'],
        status=data.get('status', 0)
    )
    
    db.session.add(printer)
    db.session.commit()
    
    return jsonify({
        'id': printer.id,
        'name': printer.name,
        'description': printer.description,
        'status': printer.status
    }), 201

@bp.route('/printers/<printer_id>', methods=['PUT'])
@admin_required
def update_printer(printer_id):
    """Update a printer (admin only)"""
    printer = Printer.query.get_or_404(printer_id)
    data = request.get_json() or {}
    
    if 'name' in data:
        printer.name = data['name']
    if 'description' in data:
        printer.description = data['description']
    if 'status' in data:
        printer.status = data['status']
    
    db.session.commit()
    
    return jsonify({
        'id': printer.id,
        'name': printer.name,
        'description': printer.description,
        'status': printer.status
    })

@bp.route('/printers/<printer_id>', methods=['DELETE'])
@admin_required
def delete_printer(printer_id):
    """Delete a printer (admin only)"""
    printer = Printer.query.get_or_404(printer_id)
    
    # Check if the printer has active jobs
    now = datetime.utcnow()
    active_jobs = PrintJob.query.filter_by(printer_id=printer.id, aborted=False) \
        .filter(PrintJob.start_at <= now) \
        .filter(PrintJob.start_at.op('+')(PrintJob.duration_in_minutes * 60) > now) \
        .all()
    
    if active_jobs:
        return jsonify({'error': 'Cannot delete printer with active jobs'}), 400
    
    db.session.delete(printer)
    db.session.commit()
    
    return jsonify({'message': 'Printer deleted successfully'})

@bp.route('/printers/availability', methods=['GET'])
def get_availability():
    """Get availability information for all printers"""
    start_date = request.args.get('start_date')
    end_date = request.args.get('end_date')
    
    if not start_date or not end_date:
        return jsonify({'error': 'start_date and end_date are required'}), 400
    
    try:
        start = datetime.fromisoformat(start_date.replace('Z', '+00:00'))
        end = datetime.fromisoformat(end_date.replace('Z', '+00:00'))
    except ValueError:
        return jsonify({'error': 'Invalid date format'}), 400
    
    if start >= end:
        return jsonify({'error': 'start_date must be before end_date'}), 400
    
    printers = Printer.query.all()
    result = []
    
    for printer in printers:
        # Get all jobs for this printer in the date range
        jobs = PrintJob.query.filter_by(printer_id=printer.id, aborted=False) \
            .filter(
                (PrintJob.start_at <= end) & 
                (PrintJob.start_at.op('+')(PrintJob.duration_in_minutes * 60) >= start)
            ) \
            .order_by(PrintJob.start_at) \
            .all()
        
        # Convert to availability slots
        availability = {
            'printer_id': printer.id,
            'printer_name': printer.name,
            'status': printer.status,
            'jobs': [job.to_dict() for job in jobs]
        }
        
        result.append(availability)
    
    return jsonify(result)