from datetime import datetime
from sqlalchemy import or_
from src.models import DatabaseContextManager
from src.models.models import (
    Course, CourseModule, CourseResource, Tutor, Student, 
    Enrollment, NotificationPreference, ResourceType
)
from flask import current_app
from src.utils import (
    custom_response,
    send_email
)
from typing import Dict
import uuid
import os

class ResourceManager:
    def __init__(self):
        pass

    def _resource_to_dict(self, resource: CourseResource, include_details: bool = False) -> Dict:
        """Convert CourseResource model to dictionary with optional detailed information"""
        base_data = {
            'id': resource.id,
            'course_id': resource.course_id,
            'module_id': resource.module_id,
            'level_id': resource.level_id,
            'title': resource.title,
            'description': resource.description,
            'resource_type': resource.resource_type.value,
            'url': resource.url,
            'file_path': resource.file_path,
            'file_size': resource.file_size,
            'duration': resource.duration,
            'is_published': resource.is_published,
            'created_at': resource.created_at.isoformat(),
            'is_required': resource.is_required,
            'views': resource.views,
            'downloads': resource.downloads,
            'license': resource.license,
            'source': resource.source,
            'difficulty_level': resource.difficulty_level
        }

        if include_details:
            base_data.update({
                'course_title': resource.course.title if resource.course else None,
                'course_code': resource.course.code if resource.course else None,
                'module_title': resource.module.title if resource.module else None,
                'level_name': resource.level.level_name if resource.level else None,
                'creator_name': f"{resource.creator.first_name} {resource.creator.last_name}" if resource.creator else None,
                'created_at_formatted': resource.created_at.strftime('%B %d, %Y at %H:%M'),
                'file_extension': os.path.splitext(resource.file_path)[1] if resource.file_path else None,
                'file_size_formatted': self._format_file_size(resource.file_size) if resource.file_size else None,
                'duration_formatted': self._format_duration(resource.duration) if resource.duration else None
            })

        return base_data

    def _format_file_size(self, size_bytes: int) -> str:
        """Format file size in human-readable format"""
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size_bytes < 1024.0:
                return f"{size_bytes:.1f} {unit}"
            size_bytes /= 1024.0
        return f"{size_bytes:.1f} TB"

    def _format_duration(self, seconds: int) -> str:
        """Format duration in human-readable format"""
        hours = seconds // 3600
        minutes = (seconds % 3600) // 60
        seconds = seconds % 60
        
        parts = []
        if hours > 0:
            parts.append(f"{hours} hour{'s' if hours > 1 else ''}")
        if minutes > 0:
            parts.append(f"{minutes} minute{'s' if minutes > 1 else ''}")
        if seconds > 0 or not parts:
            parts.append(f"{seconds} second{'s' if seconds != 1 else ''}")
            
        return ' '.join(parts)

    def create_resource(self, payload: Dict) -> Dict:
        """
        Create a new course resource
        
        Args:
            payload: {
                'course_id': str (required),
                'module_id': str (optional),
                'title': str (required),
                'description': str (optional),
                'resource_type': str (required, from ResourceType enum),
                'url': str (optional, required if no file_path),
                'file_path': str (optional, required if no url),
                'file_size': int (optional),
                'duration': int (optional, for video/audio),
                'is_required': bool (default True),
                'license': str (optional),
                'source': str (optional),
                'difficulty_level': str (optional, 'beginner', 'intermediate', 'advanced'),
                'created_by': str (tutor ID, required),
                'notify_students': bool (default False)
            }
            
        Returns:
            Response with created resource or error
        """
        with DatabaseContextManager() as ctx:
            try:
                # Validate required fields
                required_fields = ['course_id', 'title', 'resource_type', 'created_by']
                if not all(field in payload for field in required_fields):
                    return custom_response(
                        success=False,
                        data=f"Missing required fields. Required: {', '.join(required_fields)}",
                        status_code=400
                    )
                
                # Validate course exists
                course = ctx.session.query(Course).filter(
                    Course.id == payload['course_id'],
                    Course.is_active == True
                ).first()
                
                if not course:
                    return custom_response(
                        success=False,
                        data="Course not found or inactive",
                        status_code=404
                    )
                
                # Validate module if provided
                if payload.get('module_id'):
                    module = ctx.session.query(CourseModule).filter(
                        CourseModule.id == payload['module_id'],
                        CourseModule.course_id == payload['course_id']
                    ).first()
                    
                    if not module:
                        return custom_response(
                            success=False,
                            data="Module not found or doesn't belong to this course",
                            status_code=404
                        )
                
                # Validate level if provided
                if payload.get('level_id'):
                    from src.models.models import CourseLevel
                    level = ctx.session.query(CourseLevel).filter(
                        CourseLevel.id == payload['level_id'],
                        CourseLevel.course_id == payload['course_id']
                    ).first()
                    
                    if not level:
                        return custom_response(
                            success=False,
                            data="Level not found or doesn't belong to this course",
                            status_code=404
                        )
                
                # Validate creator is a tutor
                tutor = ctx.session.query(Tutor).filter(
                    Tutor.id == payload['created_by'],
                    Tutor.is_active == True
                ).first()
                
                if not tutor:
                    return custom_response(
                        success=False,
                        data="Tutor not found or inactive",
                        status_code=404
                    )
                
                # Validate resource has either URL or file path
                if not payload.get('url') and not payload.get('file_path'):
                    return custom_response(
                        success=False,
                        data="Resource must have either a URL or file path",
                        status_code=400
                    )
                
                # Validate resource type
                try:
                    resource_type = ResourceType(payload['resource_type'])
                except ValueError:
                    return custom_response(
                        success=False,
                        data=f"Invalid resource type. Valid types: {[t.value for t in ResourceType]}",
                        status_code=400
                    )
                
                # Create the resource
                resource = CourseResource(
                    id=str(uuid.uuid4()),
                    course_id=payload['course_id'],
                    module_id=payload.get('module_id'),
                    level_id=payload.get('level_id'),
                    title=payload['title'],
                    description=payload.get('description'),
                    resource_type=resource_type,
                    url=payload.get('url'),
                    file_path=payload.get('file_path'),
                    file_size=payload.get('file_size'),
                    duration=payload.get('duration'),
                    is_published=payload.get('is_published', True),
                    created_by=payload['created_by'],
                    is_required=payload.get('is_required', True),
                    license=payload.get('license'),
                    source=payload.get('source'),
                    difficulty_level=payload.get('difficulty_level')
                )
                
                ctx.session.add(resource)
                ctx.session.commit()
                
                # Notify students if requested
                if payload.get('notify_students', False):
                    self._notify_students_new_resource(ctx, resource)
                
                return custom_response(
                    success=True,
                    data=self._resource_to_dict(resource, include_details=True),
                    status_code=201
                )
                
            except Exception as e:
                ctx.session.rollback()
                current_app.logger.error(f"Failed to create resource: {str(e)}")
                return custom_response(
                    success=False,
                    data=f"Failed to create resource: {str(e)}",
                    status_code=500
                )

    def _notify_students_new_resource(self, ctx, resource: CourseResource) -> None:
        """Notify students about a new course resource"""
        # Get students through speciality relationship
        course = ctx.session.query(Course).filter(Course.id == resource.course_id).first()
        if not course:
            return []
            
        students = ctx.session.query(Student).filter(
            Student.speciality_id == course.speciality_id,
            Student.is_active == True
        ).all()
        
        for student in students:
            prefs = ctx.session.query(NotificationPreference).filter(
                NotificationPreference.user_id == student.id
            ).first()
            
            if prefs and prefs.receive_email:
                subject = f"New Resource Available: {resource.title}"
                
                # Determine resource type description
                resource_types = {
                    'document': 'Document',
                    'video': 'Video',
                    'link': 'Link',
                    'presentation': 'Presentation',
                    'image': 'Image',
                    'audio': 'Audio',
                    'archive': 'Archive',
                    'other': 'Resource'
                }
                resource_type_desc = resource_types.get(resource.resource_type.value, 'Resource')
                
                message = f"""
                <html>
                    <body>
                        <h2>New {resource_type_desc} Available</h2>
                        <p>Hello {student.first_name},</p>
                        
                        <p>A new learning resource has been added to your course:</p>
                        
                        <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; margin: 15px 0;">
                            <p><strong>Title:</strong> {resource.title}</p>
                            <p><strong>Course:</strong> {resource.course.code} - {resource.course.title}</p>
                            <p><strong>Type:</strong> {resource_type_desc}</p>
                            <p><strong>Description:</strong> {resource.description or 'No description provided'}</p>
                            <p><strong>Required:</strong> {'Yes' if resource.is_required else 'No'}</p>
                        </div>
                        
                        <div style="text-align: center; margin-top: 20px;">
                            <a href="{current_app.config['FRONTEND_URL']}/resources/{resource.id}" 
                            style="background-color: #3182ce; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">
                                View Resource
                            </a>
                        </div>
                        
                        <p>Best regards,<br>
                        {current_app.config['APP_NAME']} Team</p>
                    </body>
                </html>
                """
                
                try:
                    send_email(
                        sender_email=current_app.config['MAIL_SENDER'],
                        sender_password=current_app.config['MAIL_PASSWORD'],
                        receiver_email=student.email,
                        subject=subject,
                        message=message
                    )
                except Exception as e:
                    current_app.logger.error(f"Failed to send resource notification to student {student.id}: {str(e)}")

    def update_resource(self, resource_id: str, payload: Dict) -> Dict:
        """
        Update an existing course resource
        
        Args:
            resource_id: ID of the resource to update
            payload: Dictionary with fields to update
            
        Returns:
            Response with updated resource or error
        """
        with DatabaseContextManager() as ctx:
            try:
                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
                    )
                
                # Track if we need to notify students about changes
                notify_students = payload.get('notify_students', False)
                was_published = resource.is_published
                
                # Update fields
                if 'title' in payload:
                    resource.title = payload['title']
                if 'description' in payload:
                    resource.description = payload['description']
                if 'resource_type' in payload:
                    try:
                        resource.resource_type = ResourceType(payload['resource_type'])
                    except ValueError:
                        return custom_response(
                            success=False,
                            data=f"Invalid resource type. Valid types: {[t.value for t in ResourceType]}",
                            status_code=400
                        )
                if 'url' in payload:
                    resource.url = payload['url']
                if 'file_path' in payload:
                    resource.file_path = payload['file_path']
                if 'file_size' in payload:
                    resource.file_size = payload['file_size']
                if 'duration' in payload:
                    resource.duration = payload['duration']
                if 'is_published' in payload:
                    resource.is_published = payload['is_published']
                if 'is_required' in payload:
                    resource.is_required = payload['is_required']
                if 'license' in payload:
                    resource.license = payload['license']
                if 'source' in payload:
                    resource.source = payload['source']
                if 'difficulty_level' in payload:
                    resource.difficulty_level = payload['difficulty_level']
                
                ctx.session.commit()
                
                # Notify students if resource was just published or if explicitly requested
                if (not was_published and resource.is_published) or notify_students:
                    self._notify_students_new_resource(ctx, resource)
                
                return custom_response(
                    success=True,
                    data=self._resource_to_dict(resource, include_details=True),
                    status_code=200
                )
                
            except Exception as e:
                ctx.session.rollback()
                current_app.logger.error(f"Failed to update resource: {str(e)}")
                return custom_response(
                    success=False,
                    data=f"Failed to update resource: {str(e)}",
                    status_code=500
                )

    def get_resource(self, resource_id: str) -> Dict:
        """
        Get detailed information about a resource
        
        Args:
            resource_id: ID of the resource
            
        Returns:
            Response with resource details or error
        """
        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
                )
            
            # Increment view count
            resource.views = (resource.views or 0) + 1
            ctx.session.commit()
            
            return custom_response(
                success=True,
                data=self._resource_to_dict(resource, include_details=True),
                status_code=200
            )

    def delete_resource(self, resource_id: str) -> Dict:
        """
        Delete a course resource
        
        Args:
            resource_id: ID of the resource to delete
            
        Returns:
            Response with success/error message
        """
        with DatabaseContextManager() as ctx:
            try:
                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
                    )
                
                # TODO: In production, you might want to actually delete the file from storage here
                # before deleting the database record
                
                ctx.session.delete(resource)
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data="Resource deleted successfully",
                    status_code=200
                )
                
            except Exception as e:
                ctx.session.rollback()
                current_app.logger.error(f"Failed to delete resource: {str(e)}")
                return custom_response(
                    success=False,
                    data=f"Failed to delete resource: {str(e)}",
                    status_code=500
                )

    def get_course_resources(self, course_id: str, include_module_resources: bool = True) -> Dict:
        """
        Get all resources for a course
        
        Args:
            course_id: ID of the course
            include_module_resources: Whether to include module-specific resources
            
        Returns:
            Response with list of resources
        """
        with DatabaseContextManager() as ctx:
            # Validate course exists
            course = ctx.session.query(Course).filter(
                Course.id == course_id,
                Course.is_active == True
            ).first()
            
            if not course:
                return custom_response(
                    success=False,
                    data="Course not found or inactive",
                    status_code=404
                )
            
            # Build query
            query = ctx.session.query(CourseResource).filter(
                CourseResource.course_id == course_id
            )
            
            if not include_module_resources:
                query = query.filter(
                    CourseResource.module_id == None
                )
            
            resources = query.order_by(
                CourseResource.is_required.desc(),
                CourseResource.created_at.desc()
            ).all()
            
            return custom_response(
                success=True,
                data=[self._resource_to_dict(res, include_details=True) for res in resources],
                status_code=200
            )

    def get_module_resources(self, module_id: str) -> Dict:
        """
        Get all resources for a specific module
        
        Args:
            module_id: ID of the module
            
        Returns:
            Response with list of resources
        """
        with DatabaseContextManager() as ctx:
            # Validate module exists
            module = ctx.session.query(CourseModule).filter(
                CourseModule.id == module_id
            ).first()
            
            if not module:
                return custom_response(
                    success=False,
                    data="Module not found",
                    status_code=404
                )
            
            resources = ctx.session.query(CourseResource).filter(
                CourseResource.module_id == module_id
            ).order_by(
                CourseResource.is_required.desc(),
                CourseResource.created_at.desc()
            ).all()
            
            return custom_response(
                success=True,
                data=[self._resource_to_dict(res) for res in resources],
                status_code=200
            )

    def record_resource_download(self, resource_id: str, student_id: str) -> Dict:
        """
        Record when a student downloads a resource
        
        Args:
            resource_id: ID of the resource
            student_id: ID of the student
            
        Returns:
            Response with updated resource details
        """
        with DatabaseContextManager() as ctx:
            try:
                # Validate resource exists
                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
                    )
                
                # Validate student exists and is enrolled in the course
                enrollment = ctx.session.query(Enrollment).filter(
                    Enrollment.student_id == student_id,
                    Enrollment.course_id == resource.course_id,
                    Enrollment.status == 'active'
                ).first()
                
                if not enrollment:
                    return custom_response(
                        success=False,
                        data="Student not enrolled in this course",
                        status_code=403
                    )
                
                # Update download count
                resource.downloads = (resource.downloads or 0) + 1
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data=self._resource_to_dict(resource),
                    status_code=200
                )
                
            except Exception as e:
                ctx.session.rollback()
                current_app.logger.error(f"Failed to record download: {str(e)}")
                return custom_response(
                    success=False,
                    data=f"Failed to record download: {str(e)}",
                    status_code=500
                )

    def get_student_resource_progress(self, student_id: str, course_id: str) -> Dict:
        """
        Get a student's progress through course resources
        
        Args:
            student_id: ID of the student
            course_id: ID of the course
            
        Returns:
            Response with progress data
        """
        with DatabaseContextManager() as ctx:
            # Validate enrollment
            enrollment = ctx.session.query(Enrollment).filter(
                Enrollment.student_id == student_id,
                Enrollment.course_id == course_id,
                Enrollment.status == 'active'
            ).first()
            
            if not enrollment:
                return custom_response(
                    success=False,
                    data="Student is not enrolled in this course",
                    status_code=403
                )
            
            # Get all resources for the course
            resources = ctx.session.query(CourseResource).filter(
                CourseResource.course_id == course_id,
                CourseResource.is_published == True
            ).all()
            
            # TODO: In a real implementation, you would track which resources the student
            # has viewed/completed. This is a placeholder for that logic.
            # You would typically have a separate table to track student resource interactions.
            
            # For now, we'll just return basic stats
            total_resources = len(resources)
            required_resources = len([r for r in resources if r.is_required])
            
            return custom_response(
                success=True,
                data={
                    'student_id': student_id,
                    'course_id': course_id,
                    'total_resources': total_resources,
                    'required_resources': required_resources,
                    # Placeholder values - implement actual tracking
                    'viewed_resources': 0,
                    'completed_resources': 0,
                    'completion_percentage': 0,
                    'last_accessed': None,
                    'resources': [self._resource_to_dict(r) for r in resources]
                },
                status_code=200
            )

    def search_resources(self, course_id: str, query: str, resource_type: str = None) -> Dict:
        """
        Search for resources within a course
        
        Args:
            course_id: ID of the course
            query: Search query string
            resource_type: Optional resource type filter
            
        Returns:
            Response with matching resources
        """
        with DatabaseContextManager() as ctx:
            # Validate course exists
            course = ctx.session.query(Course).filter(
                Course.id == course_id,
                Course.is_active == True
            ).first()
            
            if not course:
                return custom_response(
                    success=False,
                    data="Course not found or inactive",
                    status_code=404
                )
            
            # Build search query
            search_query = ctx.session.query(CourseResource).filter(
                CourseResource.course_id == course_id,
                or_(
                    CourseResource.title.ilike(f'%{query}%'),
                    CourseResource.description.ilike(f'%{query}%')
                )
            )
            
            if resource_type:
                try:
                    resource_type_enum = ResourceType(resource_type)
                    search_query = search_query.filter(
                        CourseResource.resource_type == resource_type_enum
                    )
                except ValueError:
                    return custom_response(
                        success=False,
                        data=f"Invalid resource type. Valid types: {[t.value for t in ResourceType]}",
                        status_code=400
                    )
            
            resources = search_query.order_by(
                CourseResource.is_required.desc(),
                CourseResource.created_at.desc()
            ).all()
            
            return custom_response(
                success=True,
                data=[self._resource_to_dict(res) for res in resources],
                status_code=200
            )

    def get_resource_stats(self, course_id: str) -> Dict:
        """
        Get statistics about resource usage in a course
        
        Args:
            course_id: ID of the course
            
        Returns:
            Response with statistics
        """
        with DatabaseContextManager() as ctx:
            # Validate course exists
            course = ctx.session.query(Course).filter(
                Course.id == course_id,
                Course.is_active == True
            ).first()
            
            if not course:
                return custom_response(
                    success=False,
                    data="Course not found or inactive",
                    status_code=404
                )
            
            # Get all resources for the course
            resources = ctx.session.query(CourseResource).filter(
                CourseResource.course_id == course_id
            ).all()
            
            if not resources:
                return custom_response(
                    success=False,
                    data="No resources found for this course",
                    status_code=404
                )
            
            # Calculate basic stats
            total_resources = len(resources)
            total_views = sum(r.views or 0 for r in resources)
            total_downloads = sum(r.downloads or 0 for r in resources)
            avg_views = round(total_views / total_resources, 1) if total_resources else 0
            avg_downloads = round(total_downloads / total_resources, 1) if total_resources else 0
            
            # Calculate type distribution
            type_distribution = {}
            for resource in resources:
                type_name = resource.resource_type.value
                type_distribution[type_name] = type_distribution.get(type_name, 0) + 1
            
            # Calculate required vs optional
            required_count = len([r for r in resources if r.is_required])
            optional_count = total_resources - required_count
            
            return custom_response(
                success=True,
                data={
                    'course_id': course_id,
                    'course_title': course.title,
                    'total_resources': total_resources,
                    'total_views': total_views,
                    'total_downloads': total_downloads,
                    'average_views': avg_views,
                    'average_downloads': avg_downloads,
                    'type_distribution': type_distribution,
                    'required_resources': required_count,
                    'optional_resources': optional_count,
                    'most_viewed': self._resource_to_dict(max(resources, key=lambda r: r.views or 0)),
                    'most_downloaded': self._resource_to_dict(max(resources, key=lambda r: r.downloads or 0))
                },
                status_code=200
            )