import json
import secrets
import bcrypt
from datetime import datetime, timedelta
from flask import Blueprint, render_template, request, jsonify, redirect, url_for, abort, session, flash
from flask_login import current_user, login_required
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed
from wtforms import StringField, TextAreaField, IntegerField, SelectField
from wtforms.validators import DataRequired, Email, Optional, NumberRange
from functools import wraps
from sqlalchemy import desc
from sqlalchemy.orm import joinedload

from models import GuestRequest, Job, Printer, User, UserPermission, Notification, get_cached_session
from utils.logging_config import get_logger

guest_blueprint = Blueprint('guest', __name__)
logger = get_logger("guest")

# Flask-WTF Formular für Gastanfragen
class GuestRequestForm(FlaskForm):
    name = StringField('Vollständiger Name', validators=[DataRequired()])
    email = StringField('E-Mail-Adresse', validators=[DataRequired(), Email()])
    printer_id = SelectField('Drucker auswählen', coerce=int, validators=[Optional()])
    duration_min = IntegerField('Geschätzte Dauer (Minuten)', 
                               validators=[DataRequired(), NumberRange(min=1, max=1440)], 
                               default=60)
    reason = TextAreaField('Projektbeschreibung', validators=[Optional()])
    file = FileField('3D-Datei hochladen', 
                    validators=[Optional(), FileAllowed(['stl', 'obj', '3mf', 'amf', 'gcode'], 
                                                      '3D-Dateien sind erlaubt!')])

# Hilfsfunktionen
# Importiere Berechtigungsfunktionen aus utils.permissions
from utils.permissions import can_approve_jobs, approver_required

# Gast-Routen
@guest_blueprint.route('/request', methods=['GET', 'POST'])
def guest_request_form():
    """Formular für Gastanfragen anzeigen und verarbeiten."""
    with get_cached_session() as db_session:
        # Nur Drucker von TBA Marienfelde für Auswahlfelder anzeigen
        printers = db_session.query(Printer).filter(
            Printer.location == "TBA Marienfelde"
        ).all()
        
        # Formular erstellen
        form = GuestRequestForm()
        
        # Drucker-Optionen für SelectField setzen
        printer_choices = [(0, 'Keinen spezifischen Drucker auswählen')]
        printer_choices.extend([(p.id, f"{p.name} ({p.location or 'Kein Standort'})") for p in printers])
        form.printer_id.choices = printer_choices
        
        if form.validate_on_submit():
            try:
                # Daten aus dem Formular extrahieren
                name = form.name.data
                email = form.email.data
                reason = form.reason.data
                duration_min = form.duration_min.data
                printer_id = form.printer_id.data if form.printer_id.data != 0 else None
                
                # IP-Adresse erfassen
                author_ip = request.remote_addr
                
                # Drucker validieren, falls angegeben
                if printer_id:
                    printer = db_session.query(Printer).filter_by(id=printer_id, active=True).first()
                    if not printer:
                        flash("Ungültiger Drucker ausgewählt.", "error")
                        return render_template('guest_request.html', form=form, printers=printers)
                
                # Neue Anfrage erstellen
                guest_request = GuestRequest(
                    name=name,
                    email=email,
                    reason=reason,
                    duration_min=duration_min,
                    printer_id=printer_id,
                    author_ip=author_ip
                )
                
                db_session.add(guest_request)
                db_session.flush()  # Um ID zu erhalten
                
                # OTP-Code sofort generieren für Status-Abfrage
                otp_code = guest_request.generate_otp()
                guest_request.otp_expires_at = datetime.now() + timedelta(hours=72)  # 72h gültig
                
                db_session.commit()
                
                # Benachrichtigung für Genehmiger erstellen
                Notification.create_for_approvers(
                    notification_type="guest_request",
                    payload={
                        "request_id": guest_request.id,
                        "name": guest_request.name,
                        "email": guest_request.email,
                        "reason": guest_request.reason,
                        "duration_min": guest_request.duration_min,
                        "printer_name": printer.name if printer_id and printer else "Kein spezifischer Drucker",
                        "created_at": guest_request.created_at.isoformat(),
                        "status": guest_request.status,
                        "author_ip": author_ip
                    }
                )
                
                logger.info(f"Neue Gastanfrage erstellt: ID {guest_request.id}, Name: {name}, OTP generiert")
                flash("Ihr Antrag wurde erfolgreich eingereicht!", "success")
                
                # Weiterleitung zur Status-Seite mit OTP-Code-Info
                return redirect(url_for('guest.guest_request_status', request_id=guest_request.id))
                
            except Exception as e:
                logger.error(f"Fehler beim Erstellen der Gastanfrage: {str(e)}")
                flash("Fehler beim Verarbeiten Ihres Antrags. Bitte versuchen Sie es erneut.", "error")
        
        # Drucker-Liste von der Session trennen für Template-Verwendung
        db_session.expunge_all()
    
    return render_template('guest_request.html', form=form, printers=printers)

@guest_blueprint.route('/start', methods=['GET'])
def guest_start_public():
    """Öffentliche Code-Eingabe-Seite für Gäste (ohne Anmeldung)."""
    return render_template('guest_start_job.html')

@guest_blueprint.route('/job/<int:job_id>/status', methods=['GET'])
def guest_job_status(job_id):
    """Job-Status-Seite für Gäste anzeigen."""
    with get_cached_session() as db_session:
        # Job mit eager loading des printer-Relationships laden
        job = db_session.query(Job).options(
            joinedload(Job.printer),
            joinedload(Job.user)
        ).filter_by(id=job_id).first()
        
        if not job:
            abort(404, "Job nicht gefunden")
        
        # Zugehörige Gastanfrage finden
        guest_request = db_session.query(GuestRequest).filter_by(job_id=job_id).first()
        
        # Objekte explizit von der Session trennen, um sie außerhalb verwenden zu können
        db_session.expunge(job)
        if guest_request:
            db_session.expunge(guest_request)
    
    return render_template('guest_job_status.html', 
                          job=job, 
                          guest_request=guest_request)

@guest_blueprint.route('/requests/overview', methods=['GET'])
def guest_requests_overview():
    """Öffentliche Übersicht aller Druckanträge mit zensierten persönlichen Daten."""
    try:
        with get_cached_session() as db_session:
            # Alle Gastanfragen mit eager loading des printer-Relationships laden
            guest_requests = db_session.query(GuestRequest).options(
                joinedload(GuestRequest.printer)
            ).order_by(desc(GuestRequest.created_at)).all()
            
            # Daten für Gäste aufbereiten (persönliche Daten zensieren)
            public_requests = []
            for req in guest_requests:
                # Name zensieren: Nur ersten Buchstaben und letzten Buchstaben anzeigen
                censored_name = "***"
                if req.name and len(req.name) > 0:
                    if len(req.name) == 1:
                        censored_name = req.name[0] + "***"
                    elif len(req.name) == 2:
                        censored_name = req.name[0] + "***" + req.name[-1]
                    else:
                        censored_name = req.name[0] + "***" + req.name[-1]
                
                # E-Mail zensieren
                censored_email = "***@***.***"
                if req.email and "@" in req.email:
                    email_parts = req.email.split("@")
                    if len(email_parts[0]) > 2:
                        censored_email = email_parts[0][:2] + "***@" + email_parts[1]
                    else:
                        censored_email = "***@" + email_parts[1]
                
                # Grund zensieren (nur erste 20 Zeichen anzeigen)
                censored_reason = "***"
                if req.reason and len(req.reason) > 20:
                    censored_reason = req.reason[:20] + "..."
                elif req.reason:
                    censored_reason = req.reason
                
                public_requests.append({
                    "id": req.id,
                    "name": censored_name,
                    "email": censored_email,
                    "reason": censored_reason,
                    "duration_min": req.duration_min,
                    "created_at": req.created_at,
                    "status": req.status,
                    "printer": req.printer.to_dict() if req.printer else None
                })
            
            # Objekte explizit von der Session trennen
            db_session.expunge_all()
            
        return render_template('guest_requests_overview.html', requests=public_requests)
        
    except Exception as e:
        logger.error(f"Fehler beim Laden der öffentlichen Gastanfragen: {str(e)}")
        return render_template('guest_requests_overview.html', requests=[], error="Fehler beim Laden der Anfragen")

@guest_blueprint.route('/request/<int:request_id>', methods=['GET'])
def guest_request_status(request_id):
    """Status einer Gastanfrage anzeigen."""
    with get_cached_session() as db_session:
        # Guest Request mit eager loading des printer-Relationships laden
        guest_request = db_session.query(GuestRequest).options(
            joinedload(GuestRequest.printer)
        ).filter_by(id=request_id).first()
        
        if not guest_request:
            abort(404, "Anfrage nicht gefunden")
        
        # OTP-Code nur anzeigen, wenn Anfrage genehmigt wurde
        otp_code = None
        show_start_link = False
        
        if guest_request.status == "approved":
            if not guest_request.otp_code:
                # OTP generieren falls noch nicht vorhanden
                otp_code = guest_request.generate_otp()
                db_session.commit()
            else:
                # OTP existiert bereits - prüfen ob noch nicht verwendet
                show_start_link = guest_request.otp_used_at is None
        
        # Zugehörigen Job laden, falls vorhanden
        job = None
        if guest_request.job_id:
            job = db_session.query(Job).filter_by(id=guest_request.job_id).first()
            
        # Objekte explizit von der Session trennen, um sie außerhalb verwenden zu können
        db_session.expunge(guest_request)
        if job:
            db_session.expunge(job)
    
    return render_template('guest_status.html', 
                          request=guest_request, 
                          job=job,
                          otp_code=otp_code,
                          show_start_link=show_start_link)

@guest_blueprint.route('/guest/requests', methods=['GET'])
def guest_requests_by_email():
    """Guest-Requests für eine bestimmte E-Mail-Adresse anzeigen."""
    email = request.args.get('email')
    
    if not email:
        # Ohne E-Mail-Parameter zur allgemeinen Übersicht weiterleiten
        return redirect(url_for('guest.guest_requests_overview'))
    
    try:
        with get_cached_session() as db_session:
            # Guest-Requests für die angegebene E-Mail-Adresse laden
            guest_requests = db_session.query(GuestRequest).options(
                joinedload(GuestRequest.printer)
            ).filter_by(email=email).order_by(desc(GuestRequest.created_at)).all()
            
            # Jobs für die Requests laden falls vorhanden
            request_data = []
            for req in guest_requests:
                job = None
                if req.job_id:
                    job = db_session.query(Job).options(
                        joinedload(Job.printer)
                    ).filter_by(id=req.job_id).first()
                
                request_data.append({
                    'request': req,
                    'job': job
                })
            
            # Objekte von der Session trennen
            db_session.expunge_all()
            
        return render_template('guest_requests_by_email.html', 
                             requests=request_data, 
                             email=email)
        
    except Exception as e:
        logger.error(f"Fehler beim Laden der Guest-Requests für E-Mail {email}: {str(e)}")
        return render_template('guest_requests_by_email.html', 
                             requests=[], 
                             email=email,
                             error="Fehler beim Laden der Anfragen")

# API-Endpunkte
@guest_blueprint.route('/api/guest/requests', methods=['POST'])
# CSRF-Schutz wird in app.py für Guest-APIs deaktiviert
def api_create_guest_request():
    """Neue Gastanfrage erstellen."""
    data = request.get_json()
    if not data:
        return jsonify({"error": "Keine Daten erhalten"}), 400
    
    # Pflichtfelder prüfen
    name = data.get('name')
    if not name:
        return jsonify({"error": "Name ist erforderlich"}), 400
    
    # Optionale Felder
    email = data.get('email')
    reason = data.get('reason')
    duration_min = data.get('duration_min', 60)  # Standard: 1 Stunde
    printer_id = data.get('printer_id')
    
    # IP-Adresse erfassen
    author_ip = request.remote_addr
    
    try:
        with get_cached_session() as db_session:
            # Drucker prüfen
            if printer_id:
                printer = db_session.query(Printer).filter_by(id=printer_id, active=True).first()
                if not printer:
                    return jsonify({"error": "Ungültiger Drucker ausgewählt"}), 400
            
            # Neue Anfrage erstellen
            guest_request = GuestRequest(
                name=name,
                email=email,
                reason=reason,
                duration_min=duration_min,
                printer_id=printer_id,
                author_ip=author_ip
            )
            
            db_session.add(guest_request)
            db_session.flush()  # Um ID zu erhalten
            
            # OTP-Code sofort generieren für Status-Abfrage
            otp_code = guest_request.generate_otp()
            guest_request.otp_expires_at = datetime.now() + timedelta(hours=72)  # 72h gültig
            
            db_session.commit()
            
            # Benachrichtigung für Genehmiger erstellen
            Notification.create_for_approvers(
                notification_type="guest_request",
                payload={
                    "request_id": guest_request.id,
                    "name": guest_request.name,
                    "email": guest_request.email,
                    "reason": guest_request.reason,
                    "duration_min": guest_request.duration_min,
                    "printer_name": printer.name if printer_id and printer else "Kein spezifischer Drucker",
                    "created_at": guest_request.created_at.isoformat(),
                    "status": guest_request.status,
                    "author_ip": author_ip
                }
            )
            
            logger.info(f"Neue Gastanfrage erstellt: ID {guest_request.id}, Name: {name}, OTP generiert")
            
            return jsonify({
                "success": True,
                "request_id": guest_request.id,
                "status": guest_request.status,
                "otp_code": otp_code,  # Code wird nur bei Erstellung zurückgegeben
                "status_check_url": url_for('guest.guest_status_check_page', _external=True),
                "redirect_url": url_for('guest.guest_request_status', request_id=guest_request.id)
            })
            
    except Exception as e:
        logger.error(f"Fehler beim Erstellen der Gastanfrage: {str(e)}")
        return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500

@guest_blueprint.route('/api/guest/start-job', methods=['POST'])
# CSRF-Schutz wird in app.py für Guest-APIs deaktiviert
def api_start_job_with_code():
    """Job mit 6-stelligem OTP-Code starten (vereinfacht - nur Code erforderlich)."""
    try:
        data = request.get_json()
        if not data or 'code' not in data:
            return jsonify({"error": "Code ist erforderlich"}), 400
        
        code = data['code'].strip().upper()
        
        if len(code) != 6:
            return jsonify({"error": "Code muss 6 Zeichen lang sein"}), 400
        
        with get_cached_session() as db_session:
            # Gastanfrage nur anhand des OTP-Codes finden (vereinfacht)
            matching_request = GuestRequest.find_by_otp(code)
            
            if not matching_request:
                return jsonify({
                    "success": False,
                    "error": "Ungültiger Code oder Code bereits verwendet"
                }), 400
            
            # Prüfen ob zugehöriger Job existiert
            if not matching_request.job_id:
                return jsonify({
                    "success": False,
                    "error": "Kein zugehöriger Job gefunden"
                }), 400
            
            job = db_session.query(Job).options(
                joinedload(Job.printer)
            ).filter_by(id=matching_request.job_id).first()
            
            if not job:
                return jsonify({
                    "success": False,
                    "error": "Job nicht gefunden"
                }), 400
            
            # Prüfen ob Job noch startbar ist
            if job.status not in ["scheduled", "waiting_for_printer"]:
                return jsonify({
                    "success": False,
                    "error": f"Job kann im Status '{job.status}' nicht gestartet werden"
                }), 400
            
            # Job starten
            now = datetime.now()
            job.status = "running"
            job.start_at = now
            job.end_at = now + timedelta(minutes=matching_request.duration_min or matching_request.duration_minutes or 60)
            job.actual_start_time = now
            
            # OTP als verwendet markieren
            matching_request.mark_otp_used()
            
            # Drucker einschalten über Tapo-Steckdose
            if job.printer and job.printer.plug_ip:
                try:
                    from utils.job_scheduler import BackgroundTaskScheduler
                    scheduler = BackgroundTaskScheduler()
                    plug_success = scheduler.toggle_printer_plug(job.printer_id, True)
                    if plug_success:
                        logger.info(f"🔌 Drucker für Gast-Job {job.id} eingeschaltet")
                    else:
                        logger.warning(f"⚠️ Steckdose für Gast-Job {job.id} konnte nicht eingeschaltet werden")
                except Exception as e:
                    logger.warning(f"Fehler beim Einschalten des Druckers: {str(e)}")
            
            # Response-Daten vor Session-Commit sammeln
            response_data = {
                "success": True,
                "job_id": job.id,
                "job_name": job.name,
                "start_time": job.start_at.strftime("%H:%M"),
                "end_time": job.end_at.strftime("%H:%M"),
                "duration_minutes": matching_request.duration_min or matching_request.duration_minutes or 60,
                "printer_name": job.printer.name if job.printer else "Unbekannt",
                "message": f"Job '{job.name}' erfolgreich gestartet"
            }
            
            db_session.commit()
            
            logger.info(f"Job {job.id} mit 6-stelligem OTP-Code gestartet für Gastanfrage {matching_request.id}")
            
            return jsonify(response_data)
            
    except Exception as e:
        logger.error(f"Fehler beim Starten des Jobs mit Code: {str(e)}")
        return jsonify({
            "success": False,
            "error": "Fehler beim Starten des Jobs"
        }), 500

@guest_blueprint.route('/api/guest/requests/<int:request_id>', methods=['GET'])
def api_get_guest_request(request_id):
    """Status einer Gastanfrage abrufen."""
    try:
        with get_cached_session() as db_session:
            guest_request = db_session.query(GuestRequest).filter_by(id=request_id).first()
            if not guest_request:
                return jsonify({"error": "Anfrage nicht gefunden"}), 404
            
            # OTP wird nie über die API zurückgegeben
            response_data = guest_request.to_dict()
            response_data.pop("otp_code", None)
            
            return jsonify(response_data)
            
    except Exception as e:
        logger.error(f"Fehler beim Abrufen der Gastanfrage: {str(e)}")
        return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500

@guest_blueprint.route('/api/guest/job/<int:job_id>/status', methods=['GET'])
def api_get_guest_job_status(job_id):
    """Job-Status für Gäste abrufen."""
    try:
        with get_cached_session() as db_session:
            # Job mit Drucker-Information laden
            job = db_session.query(Job).options(
                joinedload(Job.printer)
            ).filter_by(id=job_id).first()
            
            if not job:
                return jsonify({"error": "Job nicht gefunden"}), 404
            
            # Zugehörige Gastanfrage prüfen
            guest_request = db_session.query(GuestRequest).filter_by(job_id=job_id).first()
            if not guest_request:
                return jsonify({"error": "Kein Gastjob"}), 403
            
            # Aktuelle Zeit für Berechnungen
            now = datetime.now()
            
            # Restzeit berechnen
            remaining_minutes = 0
            if job.status == "running" and job.end_at:
                remaining_seconds = (job.end_at - now).total_seconds()
                remaining_minutes = max(0, int(remaining_seconds / 60))
            
            # Fortschritt berechnen
            progress_percent = 0
            if job.status == "running" and job.start_at and job.end_at:
                total_duration = (job.end_at - job.start_at).total_seconds()
                elapsed_duration = (now - job.start_at).total_seconds()
                progress_percent = min(100, max(0, int((elapsed_duration / total_duration) * 100)))
            elif job.status in ["completed", "finished"]:
                progress_percent = 100
            
            job_data = {
                "id": job.id,
                "name": job.name,
                "status": job.status,
                "start_at": job.start_at.isoformat() if job.start_at else None,
                "end_at": job.end_at.isoformat() if job.end_at else None,
                "duration_minutes": job.duration_minutes,
                "remaining_minutes": remaining_minutes,
                "progress_percent": progress_percent,
                "printer": {
                    "id": job.printer.id,
                    "name": job.printer.name,
                    "location": job.printer.location
                } if job.printer else None,
                "guest_request": {
                    "id": guest_request.id,
                    "name": guest_request.name,
                    "created_at": guest_request.created_at.isoformat()
                },
                "is_active": job.status in ["scheduled", "running"],
                "is_completed": job.status in ["completed", "finished"],
                "is_failed": job.status in ["failed", "cancelled"]
            }
            
            return jsonify({
                "success": True,
                "job": job_data
            })
            
    except Exception as e:
        logger.error(f"Fehler beim Abrufen des Job-Status: {str(e)}")
        return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500

@guest_blueprint.route('/api/notifications', methods=['GET'])
@login_required
def api_get_notifications():
    """Benachrichtigungen für den aktuellen Benutzer abrufen."""
    try:
        # Zeitstempel für Filter (nur neue Benachrichtigungen)
        since = request.args.get('since')
        if since:
            try:
                since_date = datetime.fromisoformat(since)
            except ValueError:
                return jsonify({"error": "Ungültiges Datumsformat"}), 400
        else:
            since_date = None
        
        with get_cached_session() as db_session:
            query = db_session.query(Notification).filter_by(
                user_id=current_user.id,
                is_read=False
            )
            
            if since_date:
                query = query.filter(Notification.created_at > since_date)
            
            notifications = query.order_by(desc(Notification.created_at)).all()
            
            return jsonify({
                "count": len(notifications),
                "notifications": [n.to_dict() for n in notifications]
            })
            
    except Exception as e:
        logger.error(f"Fehler beim Abrufen der Benachrichtigungen: {str(e)}")
        return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500

@guest_blueprint.route('/api/notifications/<int:notification_id>/read', methods=['POST'])
@login_required
def api_mark_notification_read(notification_id):
    """Benachrichtigung als gelesen markieren."""
    try:
        with get_cached_session() as db_session:
            notification = db_session.query(Notification).filter_by(
                id=notification_id,
                user_id=current_user.id
            ).first()
            
            if not notification:
                return jsonify({"error": "Benachrichtigung nicht gefunden"}), 404
            
            notification.is_read = True
            db_session.commit()
            
            return jsonify({"success": True})
            
    except Exception as e:
        logger.error(f"Fehler beim Markieren der Benachrichtigung als gelesen: {str(e)}")
        return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500

@guest_blueprint.route('/api/admin/requests', methods=['GET'])
@approver_required
def api_get_all_requests():
    """Alle Gastanfragen für Admins abrufen."""
    try:
        # Filter-Parameter
        status_filter = request.args.get('status', 'all')  # all, pending, approved, denied
        limit = int(request.args.get('limit', 50))
        offset = int(request.args.get('offset', 0))
        
        with get_cached_session() as db_session:
            # Query mit eager loading
            query = db_session.query(GuestRequest).options(
                joinedload(GuestRequest.printer),
                joinedload(GuestRequest.job),
                joinedload(GuestRequest.processed_by_user)
            )
            
            # Status-Filter anwenden
            if status_filter != 'all':
                query = query.filter(GuestRequest.status == status_filter)
            
            # Sortierung: Pending zuerst, dann nach Erstellungsdatum
            query = query.order_by(
                desc(GuestRequest.status == 'pending'),
                desc(GuestRequest.created_at)
            )
            
            # Pagination
            total_count = query.count()
            requests = query.offset(offset).limit(limit).all()
            
            # Daten für Admin aufbereiten
            admin_requests = []
            for req in requests:
                request_data = req.to_dict()
                
                # Zusätzliche Admin-Informationen
                request_data.update({
                    "can_be_processed": req.status == "pending",
                    "is_overdue": (
                        req.status == "approved" and 
                        req.job and 
                        req.job.end_at < datetime.now()
                    ) if req.job else False,
                    "time_since_creation": (datetime.now() - req.created_at).total_seconds() / 3600 if req.created_at else 0  # Stunden
                })
                
                admin_requests.append(request_data)
            
            return jsonify({
                "success": True,
                "requests": admin_requests,
                "pagination": {
                    "total": total_count,
                    "limit": limit,
                    "offset": offset,
                    "has_more": (offset + limit) < total_count
                },
                "stats": {
                    "total": total_count,
                    "pending": db_session.query(GuestRequest).filter_by(status='pending').count(),
                    "approved": db_session.query(GuestRequest).filter_by(status='approved').count(),
                    "denied": db_session.query(GuestRequest).filter_by(status='denied').count()
                }
            })
            
    except Exception as e:
        logger.error(f"Fehler beim Abrufen der Admin-Gastanfragen: {str(e)}")
        return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500

@guest_blueprint.route('/api/admin/requests/<int:request_id>', methods=['GET'])
@approver_required
def api_get_request_details(request_id):
    """Detaillierte Informationen zu einer Gastanfrage für Admins abrufen."""
    try:
        with get_cached_session() as db_session:
            guest_request = db_session.query(GuestRequest).options(
                joinedload(GuestRequest.printer),
                joinedload(GuestRequest.job),
                joinedload(GuestRequest.processed_by_user)
            ).filter_by(id=request_id).first()
            
            if not guest_request:
                return jsonify({"error": "Anfrage nicht gefunden"}), 404
            
            # Vollständige Admin-Informationen
            request_data = guest_request.to_dict()
            
            # Verfügbare Drucker für Zuweisung
            # Alle Drucker für Auswahlfelder anzeigen (unabhängig von active-Status)
            available_printers = db_session.query(Printer).all()
            request_data["available_printers"] = [p.to_dict() for p in available_printers]
            
            # Job-Historie falls vorhanden
            if guest_request.job:
                job_data = guest_request.job.to_dict()
                job_data["is_active"] = guest_request.job.status in ["scheduled", "running"]
                job_data["is_overdue"] = guest_request.job.end_at < datetime.now() if guest_request.job.end_at else False
                request_data["job_details"] = job_data
            
            return jsonify({
                "success": True,
                "request": request_data
            })
            
    except Exception as e:
        logger.error(f"Fehler beim Abrufen der Gastanfrage-Details: {str(e)}")
        return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500

@guest_blueprint.route('/api/admin/requests/<int:request_id>/update', methods=['PUT'])
@approver_required
def api_update_request(request_id):
    """Gastanfrage aktualisieren (nur für Admins)."""
    try:
        data = request.get_json()
        if not data:
            return jsonify({"error": "Keine Daten erhalten"}), 400
        
        with get_cached_session() as db_session:
            guest_request = db_session.query(GuestRequest).filter_by(id=request_id).first()
            if not guest_request:
                return jsonify({"error": "Anfrage nicht gefunden"}), 404
            
            # Erlaubte Felder für Updates
            allowed_fields = ['printer_id', 'duration_min', 'approval_notes', 'rejection_reason']
            changes_made = False
            
            for field in allowed_fields:
                if field in data:
                    if field == 'printer_id' and data[field]:
                        # Drucker validieren
                        printer = db_session.query(Printer).filter_by(id=data[field], active=True).first()
                        if not printer:
                            return jsonify({"error": "Ungültiger Drucker ausgewählt"}), 400
                    
                    setattr(guest_request, field, data[field])
                    changes_made = True
            
            if changes_made:
                guest_request.processed_by = current_user.id
                guest_request.processed_at = datetime.now()
                db_session.commit()
                
                logger.info(f"Gastanfrage {request_id} aktualisiert von Admin {current_user.id}")
                
                return jsonify({
                    "success": True,
                    "message": "Anfrage erfolgreich aktualisiert",
                    "updated_by": current_user.name,
                    "updated_at": guest_request.processed_at.isoformat()
                })
            else:
                return jsonify({"error": "Keine Änderungen vorgenommen"}), 400
            
    except Exception as e:
        logger.error(f"Fehler beim Aktualisieren der Gastanfrage: {str(e)}")
        return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500

@guest_blueprint.route('/api/admin/requests/<int:request_id>', methods=['DELETE'])
@approver_required
def api_delete_request(request_id):
    """Gastanfrage löschen (nur für Admins)."""
    try:
        with get_cached_session() as db_session:
            guest_request = db_session.query(GuestRequest).filter_by(id=request_id).first()
            if not guest_request:
                return jsonify({"error": "Anfrage nicht gefunden"}), 404
            
            # Falls ein Job verknüpft ist, diesen auch löschen
            if guest_request.job_id:
                job = db_session.query(Job).filter_by(id=guest_request.job_id).first()
                if job:
                    db_session.delete(job)
            
            # Gastanfrage löschen
            db_session.delete(guest_request)
            db_session.commit()
            
            logger.info(f"Gastanfrage {request_id} gelöscht von Admin {current_user.id} ({current_user.username})")
            
            return jsonify({
                "success": True,
                "message": "Anfrage erfolgreich gelöscht",
                "deleted_by": current_user.username,
                "deleted_at": datetime.now().isoformat()
            })
            
    except Exception as e:
        logger.error(f"Fehler beim Löschen der Gastanfrage: {str(e)}")
        return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500

# Admin-Routen
@guest_blueprint.route('/admin/requests', methods=['GET'])
@approver_required
def admin_requests_management():
    """Admin-Oberfläche für die Verwaltung von Gastanfragen."""
    return render_template('admin_guest_requests.html')

@guest_blueprint.route('/api/requests/<int:request_id>/approve', methods=['POST'])
@approver_required
def api_approve_request(request_id):
    """Gastanfrage genehmigen."""
    try:
        data = request.get_json() or {}
        approval_notes = data.get('notes', '')
        printer_id = data.get('printer_id')  # Optional: Drucker zuweisen/ändern
        
        with get_cached_session() as db_session:
            guest_request = db_session.query(GuestRequest).filter_by(id=request_id).first()
            if not guest_request:
                return jsonify({"error": "Anfrage nicht gefunden"}), 404
            
            if guest_request.status != "pending":
                return jsonify({"error": "Anfrage wurde bereits bearbeitet"}), 400
            
            # Drucker validieren oder automatisch zuweisen
            if printer_id:
                printer = db_session.query(Printer).filter_by(id=printer_id, active=True).first()
                if not printer:
                    return jsonify({"error": "Ungültiger Drucker ausgewählt"}), 400
                guest_request.printer_id = printer_id
            elif not guest_request.printer_id:
                # Automatisch ersten verfügbaren Drucker zuweisen
                available_printer = db_session.query(Printer).filter_by(active=True).first()
                if available_printer:
                    guest_request.printer_id = available_printer.id
                    logger.info(f"Automatisch Drucker {available_printer.id} ({available_printer.name}) für Gastanfrage {request_id} zugewiesen")
                else:
                    return jsonify({"error": "Kein aktiver Drucker verfügbar. Bitte aktivieren Sie mindestens einen Drucker."}), 400
            
            # Drucker-Objekt für Job-Erstellung laden
            printer = db_session.query(Printer).filter_by(id=guest_request.printer_id).first()
            if not printer:
                return jsonify({"error": "Zugewiesener Drucker nicht gefunden"}), 400
            
            # Anfrage genehmigen
            guest_request.status = "approved"
            guest_request.processed_by = current_user.id
            guest_request.processed_at = datetime.now()
            guest_request.approval_notes = approval_notes
            
            # OTP generieren
            otp_plain = guest_request.generate_otp()
            
            # Zugehörigen Job erstellen
            start_time = datetime.now() + timedelta(minutes=5)  # Start in 5 Minuten
            end_time = start_time + timedelta(minutes=guest_request.duration_min)
            
            # Admin-Benutzer als Eigentümer verwenden
            admin_user = db_session.query(User).filter_by(is_admin=True).first()
            if not admin_user:
                admin_user = current_user  # Fallback auf aktuellen Benutzer
            
            job = Job(
                name=f"Gastauftrag: {guest_request.name}",
                description=guest_request.reason or "Gastauftrag",
                user_id=admin_user.id,
                printer_id=guest_request.printer_id,
                start_at=start_time,
                end_at=end_time,
                status="scheduled",
                duration_minutes=guest_request.duration_min,
                owner_id=admin_user.id
            )
            
            db_session.add(job)
            db_session.flush()  # ID generieren
            
            # Job-ID in Gastanfrage speichern
            guest_request.job_id = job.id
            
            db_session.commit()
            
            logger.info(f"Gastanfrage {request_id} genehmigt von Admin {current_user.id} ({current_user.username}), Drucker: {printer.name}")
            
            return jsonify({
                "success": True,
                "status": "approved",
                "job_id": job.id,
                "otp": otp_plain,  # Nur in dieser Antwort wird der OTP-Klartext zurückgegeben
                "otp_code": otp_plain,  # Für Frontend-Kompatibilität
                "printer_name": printer.name,
                "printer_id": printer.id,
                "approved_by": current_user.username,
                "approved_at": guest_request.processed_at.isoformat(),
                "notes": approval_notes,
                "message": f"Anfrage genehmigt. Zugangscode: {otp_plain}. Drucker: {printer.name}"
            })
            
    except Exception as e:
        logger.error(f"Fehler beim Genehmigen der Gastanfrage: {str(e)}")
        return jsonify({"error": f"Fehler beim Verarbeiten der Anfrage: {str(e)}"}), 500

@guest_blueprint.route('/api/requests/<int:request_id>/deny', methods=['POST'])
@approver_required
def api_deny_request(request_id):
    """Gastanfrage ablehnen."""
    try:
        data = request.get_json() or {}
        rejection_reason = data.get('reason', '')
        
        if not rejection_reason.strip():
            return jsonify({"error": "Ablehnungsgrund ist erforderlich"}), 400
        
        with get_cached_session() as db_session:
            guest_request = db_session.query(GuestRequest).filter_by(id=request_id).first()
            if not guest_request:
                return jsonify({"error": "Anfrage nicht gefunden"}), 404
            
            if guest_request.status != "pending":
                return jsonify({"error": "Anfrage wurde bereits bearbeitet"}), 400
            
            # Anfrage ablehnen
            guest_request.status = "denied"
            guest_request.processed_by = current_user.id
            guest_request.processed_at = datetime.now()
            guest_request.rejection_reason = rejection_reason
            
            db_session.commit()
            
            logger.info(f"Gastanfrage {request_id} abgelehnt von Admin {current_user.id} ({current_user.username}): {rejection_reason}")
            
            return jsonify({
                "success": True,
                "status": "denied",
                "rejected_by": current_user.username,
                "rejected_at": guest_request.processed_at.isoformat(),
                "reason": rejection_reason,
                "message": "Anfrage wurde abgelehnt"
            })
            
    except Exception as e:
        logger.error(f"Fehler beim Ablehnen der Gastanfrage: {str(e)}")
        return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500

@guest_blueprint.route('/api/admin/requests/<int:request_id>/otp', methods=['GET'])
@approver_required
def api_get_request_otp(request_id):
    """OTP-Code für genehmigte Gastanfrage abrufen (nur für Admins)."""
    try:
        with get_cached_session() as db_session:
            guest_request = db_session.query(GuestRequest).filter_by(id=request_id).first()
            if not guest_request:
                return jsonify({"error": "Anfrage nicht gefunden"}), 404
            
            if guest_request.status != "approved":
                return jsonify({"error": "Anfrage ist nicht genehmigt"}), 400
            
            if not guest_request.otp_code:
                return jsonify({"error": "Kein OTP-Code verfügbar"}), 400
            
            # Prüfen ob OTP noch gültig ist
            if guest_request.otp_expires_at and guest_request.otp_expires_at < datetime.now():
                return jsonify({
                    "error": "OTP-Code ist abgelaufen",
                    "expired": True,
                    "expired_at": guest_request.otp_expires_at.isoformat()
                }), 400
            
            # Prüfen ob OTP bereits verwendet wurde
            otp_used = guest_request.otp_used_at is not None
            
            return jsonify({
                "success": True,
                "request_id": request_id,
                "has_otp": True,
                "otp_used": otp_used,
                "otp_used_at": guest_request.otp_used_at.isoformat() if guest_request.otp_used_at else None,
                "otp_expires_at": guest_request.otp_expires_at.isoformat() if guest_request.otp_expires_at else None,
                "job_id": guest_request.job_id,
                "message": "OTP-Code wurde bei Genehmigung angezeigt und kann nicht erneut abgerufen werden" if otp_used else "OTP-Code ist bereit zur Verwendung"
            })
            
    except Exception as e:
        logger.error(f"Fehler beim Abrufen des OTP-Codes: {str(e)}")
        return jsonify({"error": "Fehler beim Abrufen des OTP-Codes"}), 500

@guest_blueprint.route('/api/guest/status', methods=['POST'])
# CSRF-Schutz wird in app.py für Guest-APIs deaktiviert
def api_guest_status_by_otp():
    """
    Öffentliche Route für Gäste um ihren Auftragsstatus mit Name + OTP-Code zu prüfen.
    Keine Authentifizierung erforderlich (Offline-System).
    """
    try:
        data = request.get_json()
        if not data:
            return jsonify({
                'success': False,
                'message': 'Keine Daten empfangen'
            }), 400
        
        otp_code = data.get('otp_code', '').strip()
        name = data.get('name', '').strip()
        
        if not otp_code:
            return jsonify({
                'success': False,
                'message': 'OTP-Code ist erforderlich'
            }), 400
        
        if not name:
            return jsonify({
                'success': False,
                'message': 'Name ist erforderlich'
            }), 400
        
        with get_cached_session() as db_session:
            # Gastanfrage mit Name + OTP-Code finden (sichere Methode)
            found_request = GuestRequest.find_by_otp_and_name(otp_code, name)
            
            if not found_request:
                logger.warning(f"Ungültiger OTP-Code oder Name für Gast-Status-Abfrage: {name} / {otp_code[:4]}****")
                return jsonify({
                    'success': False,
                    'message': 'Ungültiger Code oder Name stimmt nicht überein'
                }), 404
            
            # Status-Informationen für den Gast zusammenstellen
            status_info = {
                'id': found_request.id,
                'name': found_request.name,
                'file_name': found_request.file_name,
                'status': found_request.status,
                'created_at': found_request.created_at.isoformat() if found_request.created_at else None,
                'updated_at': found_request.updated_at.isoformat() if found_request.updated_at else None,
                'duration_min': found_request.duration_min,
                'reason': found_request.reason
            }
            
            # Status-spezifische Informationen hinzufügen
            if found_request.status == 'approved':
                status_info.update({
                    'approved_at': found_request.approved_at.isoformat() if found_request.approved_at else None,
                    'approval_notes': found_request.approval_notes,
                    'message': 'Ihr Auftrag wurde genehmigt! Sie können mit dem Drucken beginnen.',
                    'can_start_job': found_request.otp_used_at is None  # Noch nicht verwendet
                })
                
                # Job-Informationen hinzufügen falls vorhanden
                if found_request.job_id:
                    job = db_session.query(Job).options(joinedload(Job.printer)).filter_by(id=found_request.job_id).first()
                    if job:
                        status_info['job'] = {
                            'id': job.id,
                            'name': job.name,
                            'status': job.status,
                            'start_at': job.start_at.isoformat() if job.start_at else None,
                            'end_at': job.end_at.isoformat() if job.end_at else None,
                            'printer_name': job.printer.name if job.printer else None
                        }
                
            elif found_request.status == 'rejected':
                status_info.update({
                    'rejected_at': found_request.rejected_at.isoformat() if found_request.rejected_at else None,
                    'rejection_reason': found_request.rejection_reason,
                    'message': 'Ihr Auftrag wurde leider abgelehnt.'
                })
                
            elif found_request.status == 'pending':
                # Berechne wie lange der Auftrag schon wartet
                if found_request.created_at:
                    waiting_time = datetime.now() - found_request.created_at
                    hours_waiting = int(waiting_time.total_seconds() / 3600)
                    status_info.update({
                        'hours_waiting': hours_waiting,
                        'message': f'Ihr Auftrag wird bearbeitet. Wartezeit: {hours_waiting} Stunden.'
                    })
                else:
                    status_info['message'] = 'Ihr Auftrag wird bearbeitet.'
            
            # OTP als verwendet markieren (da erfolgreich abgefragt)
            db_session.commit()
            
            logger.info(f"Gast-Status-Abfrage erfolgreich für Request {found_request.id}")
            
            return jsonify({
                'success': True,
                'request': status_info
            })
        
    except Exception as e:
        logger.error(f"Fehler bei Gast-Status-Abfrage: {str(e)}")
        return jsonify({
            'success': False,
            'message': 'Fehler beim Abrufen des Status'
        }), 500

@guest_blueprint.route('/status-check')
def guest_status_check_page():
    """Status-Check-Seite für Gäste."""
    return render_template('guest_status_check.html') 