from re import A
from flask import Blueprint, request, jsonify, send_from_directory, Response, send_file
from server.permissions import editor_or_higher
from server.database import Session
from models.models import EventMedia, MediaType, Conversion, ConversionStatus
from server.task_queue import get_queue
from server.worker import convert_event_media_to_pdf
import hashlib
import os
import re

eventmedia_bp = Blueprint('eventmedia', __name__, url_prefix='/api/eventmedia')

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')


def get_param(key, default=None):
    # Reihenfolge: form > json > args
    if request.form and key in request.form:
        return request.form.get(key, default)
    if request.is_json and request.json and key in request.json:
        return request.json.get(key, default)
    return request.args.get(key, default)

# --- FileManager: List, Create Folder, Rename, Delete, Move ---


@eventmedia_bp.route('/filemanager/operations', methods=['GET', 'POST'])
@editor_or_higher
def filemanager_operations():
    action = get_param('action')
    path = get_param('path', '/')
    name = get_param('name')
    new_name = get_param('newName')
    target_path = get_param('targetPath')

    full_path = os.path.join(MEDIA_ROOT, path.lstrip('/'))

    print(action, path, name, new_name, target_path, full_path)  # Debug-Ausgabe

    # Superadmin-only protection for the converted folder
    from flask import session as flask_session
    user_role = flask_session.get('role')
    is_superadmin = user_role == 'superadmin'
    # Normalize path for checks
    norm_path = os.path.normpath('/' + path.lstrip('/'))
    under_converted = norm_path == '/converted' or norm_path.startswith('/converted/')

    if action == 'read':
        # Block listing inside converted for non-superadmins
        if under_converted and not is_superadmin:
            return jsonify({'files': [], 'cwd': {'name': os.path.basename(full_path), 'path': path}})
        # List files and folders
        items = []
        session = Session()
        for entry in os.scandir(full_path):
            item = {
                'name': entry.name,
                'isFile': entry.is_file(),
                'size': entry.stat().st_size,
                'type': os.path.splitext(entry.name)[1][1:] if entry.is_file() else '',
                'hasChild': entry.is_dir()
            }
            # Wenn Datei, versuche Upload-Datum aus DB zu holen
            if entry.is_file():
                media = session.query(EventMedia).filter_by(
                    url=entry.name).first()
                if media and media.uploaded_at:
                    # FileManager erwartet UNIX-Timestamp (Sekunden)
                    item['dateModified'] = int(media.uploaded_at.timestamp())
                else:
                    item['dateModified'] = entry.stat().st_mtime
            else:
                item['dateModified'] = entry.stat().st_mtime
            # Hide the converted folder at root for non-superadmins
            if not (not is_superadmin and not entry.is_file() and entry.name == 'converted' and (norm_path == '/' or norm_path == '')):
                items.append(item)
        session.close()
        return jsonify({'files': items, 'cwd': {'name': os.path.basename(full_path), 'path': path}})

    elif action == 'details':
        # Details für eine oder mehrere Dateien zurückgeben
        names = request.form.getlist('names[]') or (request.json.get(
            'names') if request.is_json and request.json else [])
        path = get_param('path', '/')
        details = []
        session = Session()
        for name in names:
            file_path = os.path.join(MEDIA_ROOT, path.lstrip('/'), name)
            media = session.query(EventMedia).filter_by(url=name).first()
            if os.path.isfile(file_path):
                detail = {
                    'name': name,
                    'size': os.path.getsize(file_path),
                    'dateModified': int(media.uploaded_at.timestamp()) if media and media.uploaded_at else int(os.path.getmtime(file_path)),
                    'type': os.path.splitext(name)[1][1:],
                    'hasChild': False,
                    'isFile': True,
                    'description': media.message_content if media else '',
                    # weitere Felder nach Bedarf
                }
                details.append(detail)
        session.close()
        return jsonify({'details': details})
    elif action == 'delete':
        if under_converted and not is_superadmin:
            return jsonify({'error': 'Insufficient permissions'}), 403
        for item in request.form.getlist('names[]'):
            item_path = os.path.join(full_path, item)
            if os.path.isdir(item_path):
                os.rmdir(item_path)
            else:
                os.remove(item_path)
        return jsonify({'success': True})
    elif action == 'rename':
        if under_converted and not is_superadmin:
            return jsonify({'error': 'Insufficient permissions'}), 403
        src = os.path.join(full_path, name)
        dst = os.path.join(full_path, new_name)
        os.rename(src, dst)
        return jsonify({'success': True})
    elif action == 'move':
        # Prevent moving into converted if not superadmin
        if (target_path and target_path.strip('/').split('/')[0] == 'converted') and not is_superadmin:
            return jsonify({'error': 'Insufficient permissions'}), 403
        src = os.path.join(full_path, name)
        dst = os.path.join(MEDIA_ROOT, target_path.lstrip('/'), name)
        os.rename(src, dst)
        return jsonify({'success': True})
    elif action == 'create':
        if under_converted and not is_superadmin:
            return jsonify({'error': 'Insufficient permissions'}), 403
        os.makedirs(os.path.join(full_path, name), exist_ok=True)
        return jsonify({'success': True})
    else:
        return jsonify({'error': 'Unknown action'}), 400

# --- FileManager: Upload ---


@eventmedia_bp.route('/filemanager/upload', methods=['POST'])
@editor_or_higher
def filemanager_upload():
    session = Session()
    # Korrigiert: Erst aus request.form, dann aus request.args lesen
    path = request.form.get('path') or request.args.get('path', '/')
    from flask import session as flask_session
    user_role = flask_session.get('role')
    is_superadmin = user_role == 'superadmin'
    norm_path = os.path.normpath('/' + path.lstrip('/'))
    if (norm_path == '/converted' or norm_path.startswith('/converted/')) and not is_superadmin:
        return jsonify({'error': 'Insufficient permissions'}), 403
    upload_path = os.path.join(MEDIA_ROOT, path.lstrip('/'))
    os.makedirs(upload_path, exist_ok=True)
    for file in request.files.getlist('uploadFiles'):
        file_path = os.path.join(upload_path, file.filename)
        file.save(file_path)
        ext = os.path.splitext(file.filename)[1][1:].lower()
        try:
            media_type = MediaType(ext)
        except ValueError:
            media_type = MediaType.other
        from datetime import datetime, timezone
        media = EventMedia(
            media_type=media_type,
            url=file.filename,
            file_path=os.path.relpath(file_path, MEDIA_ROOT),
            uploaded_at=datetime.now(timezone.utc)
        )
        session.add(media)
        session.commit()

        # Enqueue conversion for office presentation types
        if media_type in {MediaType.ppt, MediaType.pptx, MediaType.odp}:
            # compute file hash
            h = hashlib.sha256()
            with open(file_path, 'rb') as f:
                for chunk in iter(lambda: f.read(8192), b""):
                    h.update(chunk)
            file_hash = h.hexdigest()

            # upsert Conversion row
            conv = (
                session.query(Conversion)
                .filter_by(
                    source_event_media_id=media.id,
                    target_format='pdf',
                    file_hash=file_hash,
                )
                .one_or_none()
            )
            if not conv:
                conv = Conversion(
                    source_event_media_id=media.id,
                    target_format='pdf',
                    status=ConversionStatus.pending,
                    file_hash=file_hash,
                )
                session.add(conv)
                session.commit()

            if conv.status in {ConversionStatus.pending, ConversionStatus.failed}:
                q = get_queue()
                q.enqueue(convert_event_media_to_pdf, conv.id)

    session.commit()
    return jsonify({'success': True})

# --- FileManager: Download ---


@eventmedia_bp.route('/filemanager/download', methods=['GET'])
def filemanager_download():
    path = request.args.get('path', '/')
    from flask import session as flask_session
    user_role = flask_session.get('role')
    is_superadmin = user_role == 'superadmin'
    norm_path = os.path.normpath('/' + path.lstrip('/'))
    names = request.args.getlist('names[]')
    # Nur Einzel-Download für Beispiel
    if names:
        # Block access to converted for non-superadmins
        if (norm_path == '/converted' or norm_path.startswith('/converted/')) and not is_superadmin:
            return jsonify({'error': 'Insufficient permissions'}), 403
        file_path = os.path.join(MEDIA_ROOT, path.lstrip('/'), names[0])
        return send_from_directory(os.path.dirname(file_path), os.path.basename(file_path), as_attachment=True)
    return jsonify({'error': 'No file specified'}), 400

# --- FileManager: Get Image (optional, für Thumbnails) ---


@eventmedia_bp.route('/filemanager/get-image', methods=['GET'])
def filemanager_get_image():
    path = request.args.get('path', '/')
    from flask import session as flask_session
    user_role = flask_session.get('role')
    is_superadmin = user_role == 'superadmin'
    norm_path = os.path.normpath('/' + path.lstrip('/'))
    if (norm_path == '/converted' or norm_path.startswith('/converted/')) and not is_superadmin:
        return jsonify({'error': 'Insufficient permissions'}), 403
    file_path = os.path.join(MEDIA_ROOT, path.lstrip('/'))
    return send_from_directory(os.path.dirname(file_path), os.path.basename(file_path))

# --- EventMedia-API: Metadaten-Liste (wie gehabt) ---


@eventmedia_bp.route('', methods=['GET'])
def list_media():
    session = Session()
    media = session.query(EventMedia).all()
    return jsonify([m.to_dict() for m in media])

# --- EventMedia-API: Metadaten-Update ---


@eventmedia_bp.route('/<int:media_id>', methods=['PUT'])
@editor_or_higher
def update_media(media_id):
    session = Session()
    media = session.query(EventMedia).get(media_id)
    if not media:
        return jsonify({'error': 'Not found'}), 404
    data = request.json
    media.url = data.get('title', media.url)
    media.message_content = data.get('description', media.message_content)
    # Event-Zuordnung ggf. ergänzen
    session.commit()
    return jsonify(media.to_dict())


@eventmedia_bp.route('/find_by_filename', methods=['GET'])
def find_by_filename():
    filename = request.args.get('filename')
    if not filename:
        return jsonify({'error': 'Missing filename'}), 400
    session = Session()
    # Suche nach exaktem Dateinamen in url oder file_path
    media = session.query(EventMedia).filter(
        (EventMedia.url == filename) | (
            EventMedia.file_path.like(f"%{filename}"))
    ).first()
    if not media:
        return jsonify({'error': 'Not found'}), 404
    return jsonify({
        'id': media.id,
        'file_path': media.file_path,
        'url': media.url
    })


@eventmedia_bp.route('/<int:media_id>', methods=['GET'])
def get_media_by_id(media_id):
    session = Session()
    media = session.query(EventMedia).get(media_id)
    if not media:
        session.close()
        return jsonify({'error': 'Not found'}), 404
    result = {
        'id': media.id,
        'file_path': media.file_path,
        'url': media.url,
        'name': media.url,  # oder ein anderes Feld für den Namen
        'media_type': media.media_type.name if media.media_type else None
    }
    session.close()
    return jsonify(result)


# --- Video Streaming with Range Request Support ---
@eventmedia_bp.route('/stream/<int:media_id>/<path:filename>', methods=['GET'])
def stream_video(media_id, filename):
    """Stream video files with range request support for seeking"""
    session = Session()
    media = session.query(EventMedia).get(media_id)
    if not media or not media.file_path:
        session.close()
        return jsonify({'error': 'Video not found'}), 404
    
    file_path = os.path.join(MEDIA_ROOT, media.file_path)
    if not os.path.exists(file_path):
        session.close()
        return jsonify({'error': 'File not found'}), 404
    
    session.close()
    
    # Determine MIME type based on file extension
    ext = os.path.splitext(filename)[1].lower()
    mime_types = {
        '.mp4': 'video/mp4',
        '.webm': 'video/webm',
        '.ogv': 'video/ogg',
        '.avi': 'video/x-msvideo',
        '.mkv': 'video/x-matroska',
        '.mov': 'video/quicktime',
        '.wmv': 'video/x-ms-wmv',
        '.flv': 'video/x-flv',
        '.mpg': 'video/mpeg',
        '.mpeg': 'video/mpeg',
    }
    mime_type = mime_types.get(ext, 'video/mp4')
    
    # Support range requests for video seeking
    range_header = request.headers.get('Range', None)
    if not range_header:
        return send_file(file_path, mimetype=mime_type)
    
    size = os.path.getsize(file_path)
    byte_start, byte_end = 0, size - 1
    
    match = re.search(r'bytes=(\d+)-(\d*)', range_header)
    if match:
        byte_start = int(match.group(1))
        if match.group(2):
            byte_end = int(match.group(2))
    
    length = byte_end - byte_start + 1
    
    with open(file_path, 'rb') as f:
        f.seek(byte_start)
        data = f.read(length)
    
    response = Response(data, 206, mimetype=mime_type, direct_passthrough=True)
    response.headers.add('Content-Range', f'bytes {byte_start}-{byte_end}/{size}')
    response.headers.add('Accept-Ranges', 'bytes')
    response.headers.add('Content-Length', str(length))
    return response
