"""
Jobs Blueprint - API-Endpunkte für Job-Verwaltung
Alle Job-bezogenen API-Endpunkte sind hier zentralisiert.
"""

from flask import Blueprint, request, jsonify, current_app
from flask_login import login_required, current_user
from datetime import datetime, timedelta
from functools import wraps
from sqlalchemy.orm import joinedload

from models import get_db_session, get_cached_session, Job, Printer
from utils.logging_config import get_logger
from utils.job_queue_system import conflict_manager

# Blueprint initialisieren
jobs_blueprint = Blueprint('jobs', __name__, url_prefix='/api/jobs')

# Logger für Jobs
jobs_logger = get_logger("jobs")

def job_owner_required(f):
    """Decorator um zu prüfen, ob der aktuelle Benutzer Besitzer eines Jobs ist oder Admin"""
    @wraps(f)
    def decorated_function(job_id, *args, **kwargs):
        try:
            from models import get_cached_session
            with get_cached_session() as db_session:
                job = db_session.query(Job).filter(Job.id == job_id).first()
                
                if not job:
                    jobs_logger.warning(f"Job {job_id} nicht gefunden für Benutzer {current_user.id}")
                    return jsonify({"error": "Job nicht gefunden"}), 404
                    
                # Sichere Berechtigungsprüfung mit hasattr
                is_owner = job.user_id == int(current_user.id) or (hasattr(job, 'owner_id') and job.owner_id and job.owner_id == int(current_user.id))
                is_admin = hasattr(current_user, 'is_admin') and current_user.is_admin
                
                if not (is_owner or is_admin):
                    jobs_logger.warning(f"Benutzer {current_user.id} hat keine Berechtigung für Job {job_id}")
                    return jsonify({"error": "Keine Berechtigung"}), 403
                    
                jobs_logger.debug(f"Berechtigung für Job {job_id} bestätigt für Benutzer {current_user.id}")
                return f(job_id, *args, **kwargs)
            
        except Exception as e:
            jobs_logger.error(f"Fehler bei Berechtigungsprüfung für Job {job_id}: {str(e)}")
            return jsonify({"error": "Berechtigungsfehler", "details": str(e)}), 500
    return decorated_function

def check_printer_status(ip_address: str, timeout: int = 7):
    """Einfache Drucker-Status-Check - für erweiterte Funktionen siehe TapoStatusManager"""
    if ip_address:
        return "online", True
    return "offline", False

@jobs_blueprint.route('', methods=['GET'])
@login_required
def get_jobs():
    """Gibt alle Jobs zurück. Admins sehen alle Jobs, normale Benutzer nur ihre eigenen."""
    db_session = get_db_session()
    
    try:
        jobs_logger.info(f"📋 Jobs-Abfrage gestartet von Benutzer {current_user.id} (Admin: {current_user.is_admin})")
        
        # Paginierung unterstützen
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 50, type=int)
        status_filter = request.args.get('status')
        
        jobs_logger.debug(f"📋 Parameter: page={page}, per_page={per_page}, status_filter={status_filter}")
        
        # Query aufbauen
        query = db_session.query(Job).options(joinedload(Job.user), joinedload(Job.printer))
        
        # Admin sieht alle Jobs, User nur eigene
        if not current_user.is_admin:
            query = query.filter(Job.user_id == int(current_user.id))
            jobs_logger.debug(f"🔒 Benutzerfilter angewendet für User {current_user.id}")
        
        # Status-Filter anwenden
        if status_filter:
            query = query.filter(Job.status == status_filter)
            jobs_logger.debug(f"🏷️ Status-Filter angewendet: {status_filter}")
        
        # Sortierung: neueste zuerst
        query = query.order_by(Job.created_at.desc())
        
        # Paginierung anwenden
        offset = (page - 1) * per_page
        jobs = query.offset(offset).limit(per_page).all()
        
        # Gesamtanzahl für Paginierung
        total_count = query.count()
        
        # Convert jobs to dictionaries before closing the session
        job_dicts = [job.to_dict() for job in jobs]
        
        db_session.close()
        
        jobs_logger.info(f"✅ Jobs erfolgreich abgerufen: {len(job_dicts)} von {total_count} (Seite {page})")
        
        return jsonify({
            "success": True,
            "jobs": job_dicts,
            "total": total_count,
            "current_page": page,
            "total_pages": (total_count + per_page - 1) // per_page,
            "pagination": {
                "page": page,
                "per_page": per_page,
                "total": total_count,
                "pages": (total_count + per_page - 1) // per_page
            }
        })
    except Exception as e:
        jobs_logger.error(f"❌ Fehler beim Abrufen von Jobs: {str(e)}", exc_info=True)
        try:
            db_session.close()
        except:
            pass
        return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500

@jobs_blueprint.route('/<int:job_id>', methods=['GET'])
@login_required
@job_owner_required
def get_job(job_id):
    """Gibt einen einzelnen Job zurück."""
    try:
        jobs_logger.info(f"🔍 Job-Detail-Abfrage für Job {job_id} von Benutzer {current_user.id}")
        
        with get_cached_session() as db_session:
            # Eagerly load the user and printer relationships
            job = db_session.query(Job).options(joinedload(Job.user), joinedload(Job.printer)).filter(Job.id == job_id).first()
            
            if not job:
                jobs_logger.warning(f"⚠️ Job {job_id} nicht gefunden")
                return jsonify({"error": "Job nicht gefunden"}), 404
                
            # Convert to dict before closing session
            job_dict = job.to_dict()
        
        jobs_logger.info(f"✅ Job-Details erfolgreich abgerufen für Job {job_id}")
        return jsonify({
            "success": True,
            "job": job_dict
        })
    except Exception as e:
        jobs_logger.error(f"❌ Fehler beim Abrufen des Jobs {job_id}: {str(e)}", exc_info=True)
        return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500

@jobs_blueprint.route('', methods=['POST'])
@login_required
def create_job():
    """
    Erstellt einen neuen Job.
    
    Body: {
        "name": str (optional),
        "description": str (optional),
        "printer_id": int,
        "start_iso": str,
        "duration_minutes": int,
        "file_path": str (optional)
    }
    """
    try:
        jobs_logger.info(f"🚀 Neue Job-Erstellung gestartet von Benutzer {current_user.id}")
        
        data = request.json
        if not data:
            jobs_logger.error("❌ Keine JSON-Daten empfangen")
            return jsonify({"error": "Keine JSON-Daten empfangen"}), 400
        
        jobs_logger.debug(f"📋 Empfangene Daten: {data}")
        
        # Pflichtfelder prüfen
        required_fields = ["printer_id", "start_iso", "duration_minutes"]
        for field in required_fields:
            if field not in data:
                jobs_logger.error(f"❌ Pflichtfeld '{field}' fehlt in den Daten")
                return jsonify({"error": f"Feld '{field}' fehlt"}), 400
        
        # Daten extrahieren und validieren
        try:
            printer_id = int(data["printer_id"])
            start_iso = data["start_iso"]
            duration_minutes = int(data["duration_minutes"])
            jobs_logger.debug(f"✅ Grunddaten validiert: printer_id={printer_id}, duration={duration_minutes}")
        except (ValueError, TypeError) as e:
            jobs_logger.error(f"❌ Fehler bei Datenvalidierung: {str(e)}")
            return jsonify({"error": f"Ungültige Datenformate: {str(e)}"}), 400
        
        # Optional: Jobtitel, Beschreibung und Dateipfad
        name = data.get("name", f"Druckjob vom {datetime.now().strftime('%d.%m.%Y %H:%M')}")
        description = data.get("description", "")
        file_path = data.get("file_path")
        
        # Start-Zeit parsen
        try:
            start_at = datetime.fromisoformat(start_iso.replace('Z', '+00:00'))
            jobs_logger.debug(f"✅ Startzeit geparst: {start_at}")
        except ValueError as e:
            jobs_logger.error(f"❌ Ungültiges Startdatum '{start_iso}': {str(e)}")
            return jsonify({"error": f"Ungültiges Startdatum: {str(e)}"}), 400
        
        # Dauer validieren
        if duration_minutes <= 0:
            jobs_logger.error(f"❌ Ungültige Dauer: {duration_minutes} Minuten")
            return jsonify({"error": "Dauer muss größer als 0 sein"}), 400
        
        # End-Zeit berechnen
        end_at = start_at + timedelta(minutes=duration_minutes)
        
        db_session = get_db_session()
        
        try:
            # Prüfen, ob der Drucker existiert
            printer = db_session.query(Printer).get(printer_id)
            if not printer:
                jobs_logger.error(f"❌ Drucker mit ID {printer_id} nicht gefunden")
                db_session.close()
                return jsonify({"error": "Drucker nicht gefunden"}), 404
            
            jobs_logger.debug(f"✅ Drucker gefunden: {printer.name} (ID: {printer_id})")
            
            # ERWEITERTE KONFLIKTPRÜFUNG
            job_data = {
                'printer_id': printer_id,
                'start_time': start_at,
                'end_time': end_at,
                'priority': data.get('priority', 'normal'),
                'duration_minutes': duration_minutes
            }
            
            # Konflikte erkennen
            conflicts = conflict_manager.detect_conflicts(job_data, db_session)
            
            if conflicts:
                critical_conflicts = [c for c in conflicts if c.severity.value in ['kritisch', 'hoch']]
                if critical_conflicts:
                    # Kritische Konflikte verhindern Job-Erstellung
                    conflict_descriptions = [c.description for c in critical_conflicts]
                    jobs_logger.warning(f"⚠️ Kritische Konflikte gefunden: {conflict_descriptions}")
                    
                    db_session.close()
                    return jsonify({
                        "error": "Kritische Konflikte gefunden",
                        "conflicts": conflict_descriptions,
                        "suggestions": [s for c in critical_conflicts for s in c.suggested_solutions]
                    }), 409
                
                # Mittlere/niedrige Konflikte protokollieren aber zulassen
                jobs_logger.info(f"📋 {len(conflicts)} Konflikte erkannt, aber übergehbar")
            
            # Prüfen, ob der Drucker online ist
            printer_status, printer_active = check_printer_status(printer.plug_ip if printer.plug_ip else "")
            jobs_logger.debug(f"🖨️ Drucker-Status: {printer_status}, aktiv: {printer_active}")
            
            # Status basierend auf Drucker-Verfügbarkeit setzen
            if printer_status == "online" and printer_active:
                job_status = "scheduled"
            else:
                job_status = "waiting_for_printer"
            
            jobs_logger.info(f"📋 Job-Status festgelegt: {job_status}")
            
            # Neuen Job erstellen
            new_job = Job(
                name=name,
                description=description,
                printer_id=printer_id,
                user_id=current_user.id,
                owner_id=current_user.id,
                start_at=start_at,
                end_at=end_at,
                status=job_status,
                file_path=file_path,
                duration_minutes=duration_minutes
            )
            
            db_session.add(new_job)
            db_session.commit()
            
            # Job-Objekt für die Antwort serialisieren
            job_dict = new_job.to_dict()
            db_session.close()
            
            jobs_logger.info(f"✅ Neuer Job {new_job.id} erfolgreich erstellt für Drucker {printer_id}, Start: {start_at}, Dauer: {duration_minutes} Minuten")
            return jsonify({
                "success": True,
                "job": job_dict,
                "message": "Job erfolgreich erstellt"
            }), 201
            
        except Exception as db_error:
            jobs_logger.error(f"❌ Datenbankfehler beim Job-Erstellen: {str(db_error)}")
            try:
                db_session.rollback()
                db_session.close()
            except:
                pass
            return jsonify({"error": "Datenbankfehler beim Erstellen des Jobs", "details": str(db_error)}), 500
    
    except Exception as e:
        jobs_logger.error(f"❌ Kritischer Fehler beim Erstellen eines Jobs: {str(e)}", exc_info=True)
        return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500

@jobs_blueprint.route('/<int:job_id>', methods=['PUT'])
@login_required
@job_owner_required
def update_job(job_id):
    """Aktualisiert einen existierenden Job."""
    try:
        data = request.json
        
        db_session = get_db_session()
        job = db_session.query(Job).get(job_id)
        
        if not job:
            db_session.close()
            return jsonify({"error": "Job nicht gefunden"}), 404
        
        # Prüfen, ob der Job bearbeitet werden kann
        if job.status in ["finished", "aborted"]:
            db_session.close()
            return jsonify({"error": f"Job kann im Status '{job.status}' nicht bearbeitet werden"}), 400
        
        # Felder aktualisieren, falls vorhanden
        if "name" in data:
            job.name = data["name"]
        
        if "description" in data:
            job.description = data["description"]
        
        if "notes" in data:
            job.notes = data["notes"]
        
        if "start_iso" in data:
            try:
                new_start = datetime.fromisoformat(data["start_iso"].replace('Z', '+00:00'))
                job.start_at = new_start
                
                # End-Zeit neu berechnen falls Duration verfügbar
                if job.duration_minutes:
                    job.end_at = new_start + timedelta(minutes=job.duration_minutes)
            except ValueError:
                db_session.close()
                return jsonify({"error": "Ungültiges Startdatum"}), 400
        
        if "duration_minutes" in data:
            duration = int(data["duration_minutes"])
            if duration <= 0:
                db_session.close()
                return jsonify({"error": "Dauer muss größer als 0 sein"}), 400
            
            job.duration_minutes = duration
            # End-Zeit neu berechnen
            if job.start_at:
                job.end_at = job.start_at + timedelta(minutes=duration)
        
        # Aktualisierungszeitpunkt setzen
        job.updated_at = datetime.now()
        
        db_session.commit()
        
        # Job-Objekt für die Antwort serialisieren
        job_dict = job.to_dict()
        db_session.close()
        
        jobs_logger.info(f"Job {job_id} aktualisiert")
        return jsonify({
            "success": True,
            "job": job_dict,
            "message": "Job erfolgreich aktualisiert"
        })
    
    except Exception as e:
        jobs_logger.error(f"Fehler beim Aktualisieren von Job {job_id}: {str(e)}")
        return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500

@jobs_blueprint.route('/<int:job_id>', methods=['DELETE'])
@login_required
@job_owner_required
def delete_job(job_id):
    """Löscht einen Job."""
    db_session = None
    try:
        jobs_logger.info(f"🗑️ Lösche Job {job_id} für Benutzer {current_user.id}")
        
        db_session = get_db_session()
        job = db_session.query(Job).get(job_id)
        
        if not job:
            jobs_logger.warning(f"Job {job_id} nicht gefunden beim Löschen")
            return jsonify({"error": "Job nicht gefunden"}), 404
        
        # Prüfen, ob der Job gelöscht werden kann
        if job.status == "running":
            jobs_logger.warning(f"Versuch, laufenden Job {job_id} zu löschen")
            return jsonify({"error": "Laufende Jobs können nicht gelöscht werden"}), 400
        
        job_name = job.name or f"Job-{job_id}"
        
        # Abhängige Datensätze vor Job-Löschung bereinigen
        jobs_logger.debug(f"🧹 Bereinige abhängige Datensätze für Job {job_id}")
        
        # 1. JobOrder-Einträge löschen (NOT NULL foreign key)
        from models import JobOrder, GuestRequest
        job_orders_deleted = db_session.query(JobOrder).filter(JobOrder.job_id == job_id).delete()
        if job_orders_deleted > 0:
            jobs_logger.debug(f"🗑️ {job_orders_deleted} JobOrder-Einträge gelöscht")
        
        # 2. GuestRequest job_id auf NULL setzen (NULLABLE foreign key)
        guest_requests_updated = db_session.query(GuestRequest).filter(GuestRequest.job_id == job_id).update({GuestRequest.job_id: None})
        if guest_requests_updated > 0:
            jobs_logger.debug(f"🔄 {guest_requests_updated} GuestRequest-Einträge aktualisiert")
        
        # 3. Jetzt Job sicher löschen
        db_session.delete(job)
        db_session.commit()
        
        jobs_logger.info(f"✅ Job '{job_name}' (ID: {job_id}) erfolgreich gelöscht von Benutzer {current_user.id}")
        return jsonify({
            "success": True, 
            "message": "Job erfolgreich gelöscht",
            "deleted_job": {
                "id": job_id,
                "name": job_name
            }
        })
        
    except Exception as e:
        jobs_logger.error(f"❌ Fehler beim Löschen des Jobs {job_id}: {str(e)}", exc_info=True)
        if db_session:
            try:
                db_session.rollback()
            except:
                pass
        return jsonify({
            "error": "Interner Serverfehler beim Löschen des Jobs",
            "details": str(e) if current_app.debug else None
        }), 500
    finally:
        if db_session:
            try:
                db_session.close()
            except:
                pass

@jobs_blueprint.route('/active', methods=['GET'])
@login_required
def get_active_jobs():
    """Gibt alle aktiven Jobs zurück."""
    try:
        db_session = get_db_session()
        
        query = db_session.query(Job).options(
            joinedload(Job.user), 
            joinedload(Job.printer)
        ).filter(
            Job.status.in_(["scheduled", "running"])
        )
        
        # Normale Benutzer sehen nur ihre eigenen aktiven Jobs
        if not current_user.is_admin:
            query = query.filter(Job.user_id == current_user.id)
        
        active_jobs = query.all()
        
        result = []
        for job in active_jobs:
            job_dict = job.to_dict()
            # Aktuelle Restzeit berechnen
            if job.status == "running" and job.end_at:
                remaining_time = job.end_at - datetime.now()
                if remaining_time.total_seconds() > 0:
                    job_dict["remaining_minutes"] = int(remaining_time.total_seconds() / 60)
                else:
                    job_dict["remaining_minutes"] = 0
            
            result.append(job_dict)
        
        db_session.close()
        return jsonify({
            "success": True,
            "jobs": result,
            "total": len(result)
        })
    except Exception as e:
        jobs_logger.error(f"Fehler beim Abrufen aktiver Jobs: {str(e)}")
        return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500

@jobs_blueprint.route('/current', methods=['GET'])
@login_required
def get_current_job():
    """Gibt den aktuell laufenden Job für den eingeloggten Benutzer zurück."""
    db_session = get_db_session()
    
    try:
        current_job = db_session.query(Job).filter(
            Job.user_id == current_user.id,
            Job.status == "running"
        ).first()
        
        if current_job:
            job_dict = current_job.to_dict()
            db_session.close()
            return jsonify({
                "success": True,
                "job": job_dict
            })
        else:
            db_session.close()
            return jsonify({
                "success": False,
                "message": "Kein aktueller Job"
            }), 404
    except Exception as e:
        jobs_logger.error(f"Fehler beim Abrufen des aktuellen Jobs: {str(e)}")
        db_session.close()
        return jsonify({"error": "Interner Serverfehler"}), 500

@jobs_blueprint.route('/recent', methods=['GET'])
@login_required
def get_recent_jobs():
    """Gibt die letzten Jobs zurück (für Dashboard)."""
    db_session = get_db_session()
    
    try:
        jobs_logger.info(f"📋 Recent Jobs-Abfrage von Benutzer {current_user.id}")
        
        # Anzahl der Jobs begrenzen
        limit = request.args.get('limit', 10, type=int)
        if limit > 50:  # Sicherheitslimit
            limit = 50
        
        # Query aufbauen
        query = db_session.query(Job).options(joinedload(Job.user), joinedload(Job.printer))
        
        # Admin sieht alle Jobs, User nur eigene
        if not current_user.is_admin:
            query = query.filter(Job.user_id == int(current_user.id))
        
        # Sortierung: neueste zuerst, begrenzt auf limit
        recent_jobs = query.order_by(Job.created_at.desc()).limit(limit).all()
        
        # Convert jobs to dictionaries
        job_dicts = [job.to_dict() for job in recent_jobs]
        
        db_session.close()
        
        jobs_logger.info(f"✅ {len(job_dicts)} Recent Jobs erfolgreich abgerufen")
        
        return jsonify({
            "success": True,
            "jobs": job_dicts,
            "total": len(job_dicts)
        })
    except Exception as e:
        jobs_logger.error(f"❌ Fehler beim Abrufen der Recent Jobs: {str(e)}", exc_info=True)
        try:
            db_session.close()
        except:
            pass
        return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500

@jobs_blueprint.route('/<int:job_id>/start', methods=['POST'])
@login_required
@job_owner_required
def start_job(job_id):
    """Startet einen Job manuell."""
    try:
        db_session = get_db_session()
        job = db_session.query(Job).options(joinedload(Job.printer)).get(job_id)
        
        if not job:
            db_session.close()
            return jsonify({"error": "Job nicht gefunden"}), 404
        
        # Prüfen, ob der Job gestartet werden kann
        if job.status not in ["scheduled", "waiting_for_printer"]:
            db_session.close()
            return jsonify({"error": f"Job kann im Status '{job.status}' nicht gestartet werden"}), 400
        
        # Drucker-Status prüfen
        if job.printer.plug_ip:
            status, active = check_printer_status(job.printer.plug_ip)
            if status != "online" or not active:
                db_session.close()
                return jsonify({"error": "Drucker ist nicht online"}), 400
        
        # Drucker einschalten über Tapo-Steckdose
        from utils.job_scheduler import BackgroundTaskScheduler
        scheduler = BackgroundTaskScheduler()
        plug_success = scheduler.toggle_printer_plug(job.printer_id, True)
        
        if not plug_success:
            jobs_logger.warning(f"⚠️ Steckdose für Job {job_id} konnte nicht eingeschaltet werden")
        
        # Job als laufend markieren
        job.status = "running"
        job.start_at = datetime.now()
        job.end_at = job.start_at + timedelta(minutes=job.duration_minutes)
        
        db_session.commit()
        
        if plug_success:
            jobs_logger.info(f"🔌 Drucker für Job {job_id} eingeschaltet")
        
        # Job-Objekt für die Antwort serialisieren
        job_dict = job.to_dict()
        db_session.close()
        
        jobs_logger.info(f"Job {job_id} manuell gestartet")
        return jsonify({"job": job_dict})
    
    except Exception as e:
        jobs_logger.error(f"Fehler beim Starten von Job {job_id}: {str(e)}")
        return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500

@jobs_blueprint.route('/<int:job_id>/pause', methods=['POST'])
@login_required
@job_owner_required
def pause_job(job_id):
    """Pausiert einen laufenden Job."""
    try:
        db_session = get_db_session()
        job = db_session.query(Job).get(job_id)
        
        if not job:
            db_session.close()
            return jsonify({"error": "Job nicht gefunden"}), 404
        
        # Prüfen, ob der Job pausiert werden kann
        if job.status != "running":
            db_session.close()
            return jsonify({"error": f"Job kann im Status '{job.status}' nicht pausiert werden"}), 400
        
        # Job pausieren
        job.status = "paused"
        
        db_session.commit()
        
        # Job-Objekt für die Antwort serialisieren
        job_dict = job.to_dict()
        db_session.close()
        
        jobs_logger.info(f"Job {job_id} pausiert")
        return jsonify({"job": job_dict})
    
    except Exception as e:
        jobs_logger.error(f"Fehler beim Pausieren von Job {job_id}: {str(e)}")
        return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500

@jobs_blueprint.route('/<int:job_id>/resume', methods=['POST'])
@login_required
@job_owner_required
def resume_job(job_id):
    """Setzt einen pausierten Job fort."""
    try:
        db_session = get_db_session()
        job = db_session.query(Job).get(job_id)
        
        if not job:
            db_session.close()
            return jsonify({"error": "Job nicht gefunden"}), 404
        
        # Prüfen, ob der Job fortgesetzt werden kann
        if job.status != "paused":
            db_session.close()
            return jsonify({"error": f"Job kann im Status '{job.status}' nicht fortgesetzt werden"}), 400
        
        # Job fortsetzen
        job.status = "running"
        
        db_session.commit()
        
        # Job-Objekt für die Antwort serialisieren
        job_dict = job.to_dict()
        db_session.close()
        
        jobs_logger.info(f"Job {job_id} fortgesetzt")
        return jsonify({"job": job_dict})
    
    except Exception as e:
        jobs_logger.error(f"Fehler beim Fortsetzen von Job {job_id}: {str(e)}")
        return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500

@jobs_blueprint.route('/<int:job_id>/finish', methods=['POST'])
@login_required
def finish_job(job_id):
    """Beendet einen Job manuell."""
    try:
        db_session = get_db_session()
        job = db_session.query(Job).options(joinedload(Job.printer)).get(job_id)
        
        if not job:
            db_session.close()
            return jsonify({"error": "Job nicht gefunden"}), 404
        
        # Berechtigung prüfen
        is_owner = job.user_id == int(current_user.id) or job.owner_id == int(current_user.id)
        is_admin = current_user.is_admin
        
        if not (is_owner or is_admin):
            db_session.close()
            return jsonify({"error": "Keine Berechtigung"}), 403
        
        # Prüfen, ob der Job beendet werden kann
        if job.status not in ["scheduled", "running", "paused"]:
            db_session.close()
            return jsonify({"error": f"Job kann im Status '{job.status}' nicht beendet werden"}), 400
        
        # Job als beendet markieren
        job.status = "finished"
        job.actual_end_time = datetime.now()
        
        db_session.commit()
        
        # Job-Objekt für die Antwort serialisieren
        job_dict = job.to_dict()
        db_session.close()
        
        jobs_logger.info(f"Job {job_id} manuell beendet durch Benutzer {current_user.id}")
        return jsonify({"job": job_dict})
    
    except Exception as e:
        jobs_logger.error(f"Fehler beim manuellen Beenden von Job {job_id}: {str(e)}")
        return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500 