from flask.views import MethodView
from flask_smorest import Blueprint
from src.views.resources.utils import ResourceManager
from flask import request, current_app
from werkzeug.utils import secure_filename
from src.utils import custom_response
import os
import uuid

resource_router = Blueprint("Course Resources Management Routes", __name__, description="Operations on course resources")

@resource_router.route("/course-resources")
class CourseResourceRouter(MethodView):
    def __init__(self) -> None:
        self.resource_manager = ResourceManager()

    def post(self):
        """Upload a course resource (document, video, etc.)"""
        try:
            # Check if file is in request
            if 'file' not in request.files:
                return custom_response(
                    success=False,
                    data="No file provided",
                    status_code=400
                )
            
            file = request.files['file']
            if file.filename == '':
                return custom_response(
                    success=False,
                    data="No file selected",
                    status_code=400
                )
            
            # Get form data
            title = request.form.get('title')
            description = request.form.get('description')
            resource_type = request.form.get('resource_type', 'document')
            is_required = request.form.get('is_required', 'true').lower() == 'true'
            course_id = request.form.get('course_id')
            uploader_id = request.form.get('uploader_id')
            module_id = request.form.get('module_id')  # Optional
            
            # Validate required fields
            if not all([title, course_id, uploader_id]):
                return custom_response(
                    success=False,
                    data="Missing required fields: title, course_id, uploader_id",
                    status_code=400
                )
            
            # Secure filename
            filename = secure_filename(file.filename)
            file_extension = filename.rsplit('.', 1)[1].lower() if '.' in filename else ''
            
            # Validate file type based on resource_type
            allowed_extensions = {
                'video': ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv'],
                'document': ['pdf', 'doc', 'docx', 'txt', 'ppt', 'pptx', 'xls', 'xlsx'],
                'image': ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg'],
                'audio': ['mp3', 'wav', 'ogg', 'flac'],
                'presentation': ['ppt', 'pptx', 'key', 'odp'],
                'archive': ['zip', 'rar', '7z', 'tar', 'gz']
            }
            
            if resource_type in allowed_extensions:
                if file_extension not in allowed_extensions[resource_type]:
                    return custom_response(
                        success=False,
                        data=f"Invalid file type for {resource_type}. Allowed: {', '.join(allowed_extensions[resource_type])}",
                        status_code=400
                    )
            
            # Create upload directory based on resource type
            # Get the absolute path to the server_api directory
            server_base = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
            upload_base = current_app.config.get('UPLOAD_FOLDER', os.path.join(server_base, 'uploads'))
            
            # Ensure upload_base is absolute
            if not os.path.isabs(upload_base):
                upload_base = os.path.join(server_base, upload_base)
            
            upload_dir = os.path.join(upload_base, 'course_resources', resource_type)
            os.makedirs(upload_dir, exist_ok=True)
            
            # Generate unique filename
            file_id = str(uuid.uuid4())
            unique_filename = f"{file_id}.{file_extension}" if file_extension else file_id
            file_path = os.path.join(upload_dir, unique_filename)
            
            # Save file
            file.save(file_path)
            file_size = os.path.getsize(file_path)
            
            current_app.logger.info(f"File saved to: {file_path}")
            
            # For videos, you could process them here (e.g., generate thumbnails, transcode)
            duration = None
            if resource_type == 'video':
                try:
                    # Placeholder for video processing
                    # In production, you would use ffmpeg or similar to:
                    # 1. Extract video metadata (duration, resolution)
                    # 2. Generate thumbnail
                    # 3. Optionally transcode to web-friendly format
                    # 4. Extract audio track
                    # For now, we'll just log that a video was uploaded
                    current_app.logger.info(f"Video uploaded: {unique_filename}, processing can be added here")
                    
                    # You could use moviepy or ffmpeg-python to get duration
                    # from moviepy.editor import VideoFileClip
                    # video = VideoFileClip(file_path)
                    # duration = int(video.duration)
                    # video.close()
                except Exception as e:
                    current_app.logger.error(f"Error processing video: {str(e)}")
            
            # Create resource in database
            level_id = request.form.get('level_id')
            
            resource_data = {
                'course_id': course_id,
                'module_id': module_id if module_id else None,
                'level_id': level_id if level_id else None,
                'title': title,
                'description': description,
                'resource_type': resource_type,
                'file_path': file_path,
                'file_size': file_size,
                'duration': duration,
                'is_required': is_required,
                'created_by': uploader_id,
                'is_published': True,
                'notify_students': request.form.get('notify_students', 'false').lower() == 'true'
            }
            
            return self.resource_manager.create_resource(resource_data)
            
        except Exception as e:
            current_app.logger.error(f"Error uploading resource: {str(e)}")
            return custom_response(
                success=False,
                data=f"Error uploading file: {str(e)}",
                status_code=500
            )

@resource_router.route("/course-resources/<string:resource_id>")
class CourseResourceDetailRouter(MethodView):
    def __init__(self) -> None:
        self.resource_manager = ResourceManager()

    def get(self, resource_id):
        """Get resource details"""
        return self.resource_manager.get_resource(resource_id)

    def put(self, resource_id):
        """Update resource details"""
        payload = request.get_json()
        return self.resource_manager.update_resource(resource_id, payload)

    def delete(self, resource_id):
        """Delete a resource"""
        return self.resource_manager.delete_resource(resource_id)

@resource_router.route("/course-resources/<string:resource_id>/download")
class CourseResourceDownloadRouter(MethodView):
    def __init__(self) -> None:
        self.resource_manager = ResourceManager()

    def get(self, resource_id):
        """Download a resource file"""
        from flask import send_file
        from src.models import DatabaseContextManager
        from src.models.models import CourseResource
        
        # Get resource and correct file path
        with DatabaseContextManager() as ctx:
            resource = ctx.session.query(CourseResource).filter(
                CourseResource.id == resource_id
            ).first()
            
            if not resource:
                return custom_response(
                    success=False,
                    data="Resource not found",
                    status_code=404
                )
            
            if not resource.file_path:
                return custom_response(
                    success=False,
                    data="Resource has no file path",
                    status_code=404
                )
            
            # Get the actual file path, handling incorrect paths
            actual_file_path = resource.file_path
            download_name = resource.title
            
            # Get server base directory (server_api folder)
            server_base = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
            
            # Handle relative paths by making them absolute
            if not os.path.isabs(actual_file_path):
                # Path is relative, make it absolute from server_base
                actual_file_path = os.path.join(server_base, actual_file_path)
            
            if not os.path.exists(actual_file_path):
                # Try to find the file in the correct location
                filename = os.path.basename(resource.file_path)
                
                # Get resource type safely
                resource_type = resource.resource_type.value if hasattr(resource.resource_type, 'value') else str(resource.resource_type)
                
                # Try different possible locations
                possible_paths = [
                    os.path.join(server_base, 'uploads', 'course_resources', resource_type, filename),
                    os.path.join(server_base, 'uploads', 'course_resources', 'video', filename),
                ]
                
                found_path = None
                for path in possible_paths:
                    if os.path.exists(path):
                        found_path = path
                        break
                
                if not found_path:
                    return custom_response(
                        success=False,
                        data="Resource file not found",
                        status_code=404
                    )
                
                # Use the found path
                actual_file_path = found_path
                resource.file_path = found_path
            
            # Increment download count
            resource.downloads = (resource.downloads or 0) + 1
            ctx.session.commit()
        
        # Send file outside context manager
        try:
            return send_file(
                actual_file_path,
                as_attachment=True,
                download_name=download_name
            )
        except Exception as e:
            current_app.logger.error(f"Error downloading file: {str(e)}")
            return custom_response(
                success=False,
                data=f"Error downloading file: {str(e)}",
                status_code=500
            )

@resource_router.route("/course-resources/<string:resource_id>/stream")
class CourseResourceStreamRouter(MethodView):
    def __init__(self) -> None:
        self.resource_manager = ResourceManager()

    def get(self, resource_id):
        """Stream a video resource"""
        from flask import send_file, Response
        from src.models import DatabaseContextManager
        from src.models.models import CourseResource
        import mimetypes
        
        # First, get the resource and determine the file path
        with DatabaseContextManager() as ctx:
            resource = ctx.session.query(CourseResource).filter(
                CourseResource.id == resource_id
            ).first()
            
            if not resource:
                current_app.logger.error(f"Resource not found: {resource_id}")
                return custom_response(
                    success=False,
                    data="Resource not found",
                    status_code=404
                )
            
            current_app.logger.info(f"Streaming resource: {resource.title}")
            current_app.logger.info(f"File path from DB: {resource.file_path}")
            
            if not resource.file_path:
                current_app.logger.error(f"No file path for resource: {resource_id}")
                return custom_response(
                    success=False,
                    data="Resource has no file path",
                    status_code=404
                )
            
            # Get the actual file path, handling incorrect paths
            actual_file_path = resource.file_path
            current_app.logger.info(f"Original path from DB: {actual_file_path}")
            
            # Get server base directory (server_api folder)
            # __file__ is in server_api/src/views/resources/__init__.py
            # So we need 4 dirname calls to get to server_api
            server_base = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
            current_app.logger.info(f"Server base: {server_base}")
            
            # Handle relative paths by making them absolute
            if not os.path.isabs(actual_file_path):
                # Path is relative, make it absolute from server_base
                actual_file_path = os.path.join(server_base, actual_file_path)
                current_app.logger.info(f"Converted relative path to absolute: {actual_file_path}")
            
            current_app.logger.info(f"Checking if file exists at: {actual_file_path}")
            current_app.logger.info(f"File exists: {os.path.exists(actual_file_path)}")
            
            # If file still doesn't exist, try alternative locations
            if not os.path.exists(actual_file_path):
                current_app.logger.warning(f"File not found at computed path: {actual_file_path}")
                
                filename = os.path.basename(resource.file_path)
                
                # Get resource type safely
                resource_type = resource.resource_type.value if hasattr(resource.resource_type, 'value') else str(resource.resource_type)
                
                current_app.logger.info(f"Filename: {filename}")
                current_app.logger.info(f"Resource type: {resource_type}")
                
                # Try different possible locations
                possible_paths = [
                    os.path.join(server_base, 'uploads', 'course_resources', resource_type, filename),
                    os.path.join(server_base, 'uploads', 'course_resources', 'video', filename),
                    os.path.join(server_base, 'src', 'uploads', 'course_resources', resource_type, filename),
                ]
                
                found_path = None
                for path in possible_paths:
                    current_app.logger.info(f"Trying path: {path}")
                    if os.path.exists(path):
                        found_path = path
                        current_app.logger.info(f"✓ Found file at: {path}")
                        break
                    else:
                        current_app.logger.warning(f"✗ Not found at: {path}")
                
                if not found_path:
                    current_app.logger.error(f"Could not find file anywhere!")
                    return custom_response(
                        success=False,
                        data=f"Resource file not found. Please re-upload the video.",
                        status_code=404
                    )
                
                # Use the found path and update the database with absolute path
                actual_file_path = found_path
                resource.file_path = found_path
                current_app.logger.info(f"Updated database path to: {found_path}")
            
            # Increment view count
            resource.views = (resource.views or 0) + 1
            
            # Get resource type for MIME type
            resource_type_value = resource.resource_type.value if hasattr(resource.resource_type, 'value') else str(resource.resource_type)
            
            ctx.session.commit()
        
        # Now stream the file (outside the context manager to avoid locking issues)
        try:
            # Get MIME type using the actual file path
            mime_type, _ = mimetypes.guess_type(actual_file_path)
            if not mime_type:
                mime_type = 'video/mp4'  # Default to mp4
            
            current_app.logger.info(f"About to stream file: {actual_file_path}")
            current_app.logger.info(f"File exists before streaming: {os.path.exists(actual_file_path)}")
            current_app.logger.info(f"MIME type: {mime_type}")
            
            # Return file for streaming with proper headers
            return send_file(
                actual_file_path,
                mimetype=mime_type,
                as_attachment=False,
                conditional=True  # Enable range requests for seeking
            )
        except Exception as e:
            current_app.logger.error(f"Error streaming file: {str(e)}")
            current_app.logger.error(f"Attempted path: {actual_file_path}")
            return custom_response(
                success=False,
                data=f"Error streaming file: {str(e)}",
                status_code=500
            )

@resource_router.route("/courses/<string:course_id>/resources")
class CourseResourcesListRouter(MethodView):
    def __init__(self) -> None:
        self.resource_manager = ResourceManager()

    def get(self, course_id):
        """Get all resources for a course"""
        include_module_resources = request.args.get('include_module_resources', 'true').lower() == 'true'
        return self.resource_manager.get_course_resources(course_id, include_module_resources)

@resource_router.route("/modules/<string:module_id>/resources")
class ModuleResourcesRouter(MethodView):
    def __init__(self) -> None:
        self.resource_manager = ResourceManager()

    def get(self, module_id):
        """Get all resources for a module"""
        return self.resource_manager.get_module_resources(module_id)

@resource_router.route("/course-resources/<string:resource_id>/debug")
class CourseResourceDebugRouter(MethodView):
    def get(self, resource_id):
        """Debug endpoint to check resource details"""
        from src.models import DatabaseContextManager
        from src.models.models import CourseResource
        
        with DatabaseContextManager() as ctx:
            resource = ctx.session.query(CourseResource).filter(
                CourseResource.id == resource_id
            ).first()
            
            if not resource:
                return {"error": "Resource not found", "resource_id": resource_id}, 404
            
            server_base = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
            
            return {
                "resource_id": resource.id,
                "title": resource.title,
                "stored_file_path": resource.file_path,
                "file_exists_at_stored_path": os.path.exists(resource.file_path) if resource.file_path else False,
                "server_base": server_base,
                "expected_path": os.path.join(server_base, 'uploads', 'course_resources', 'video', os.path.basename(resource.file_path) if resource.file_path else ''),
                "file_exists_at_expected_path": os.path.exists(os.path.join(server_base, 'uploads', 'course_resources', 'video', os.path.basename(resource.file_path))) if resource.file_path else False
            }, 200

