<?php
/**
 * SmartThink LMS - Course Class
 * 
 * Handles course management, enrollment, and content delivery
 */

require_once __DIR__ . '/Cohort.php';

class Course {
    private $db;
    private $table = 'courses';
    
    public function __construct() {
        $this->db = Database::getInstance();
    }
    
    /**
     * Create new course
     */
    public function create($data) {
        // Validate required fields
        $required = ['title', 'description', 'category_id', 'instructor_id'];
        foreach ($required as $field) {
            if (empty($data[$field])) {
                throw new Exception("Field '$field' is required");
            }
        }
        
        // Generate slug from title
        $data['slug'] = $this->generateSlug($data['title']);
        
        // Check if slug exists
        if ($this->getBySlug($data['slug'])) {
            $data['slug'] .= '-' . time();
        }
        
        // Set default values
        // Preserve provided status (e.g., publish on create when requested)
        if (empty($data['status'])) {
            $data['status'] = 'draft';
        }
        $data['created_at'] = formatDate();
        $data['created_by'] = getCurrentUserId();
        
        // Set region if not provided
        if (empty($data['region'])) {
            $data['region'] = $_SESSION['region'] ?? 'global';
        }
        
        // Validate instructor exists and has proper role
        $instructor = $this->db->get("SELECT * FROM users WHERE id = ?", [$data['instructor_id']]);
        if (!$instructor) {
            throw new Exception("Instructor not found");
        }
        
        // Insert course
        $courseId = $this->db->insert($this->table, $data);
        
        if (!$courseId) {
            throw new Exception("Failed to create course");
        }
        
        // Log activity
        $this->logActivity(getCurrentUserId(), 'course_created', "Course '{$data['title']}' created", 'course', $courseId);
        
        return $courseId;
    }
    
    /**
     * Update course
     */
    public function update($courseId, $data) {
        // Check if course exists
        $course = $this->getById($courseId);
        if (!$course) {
            throw new Exception("Course not found");
        }
        
        // Check permissions
        if (!$this->canEditCourse($courseId)) {
            throw new Exception("You don't have permission to edit this course");
        }
        
        // Remove sensitive fields
        unset($data['id'], $data['created_at'], $data['created_by']);
        
        // Update slug if title changed
        if (isset($data['title']) && $data['title'] !== $course['title']) {
            $data['slug'] = $this->generateSlug($data['title']);
            
            // Check if new slug exists
            if ($this->getBySlug($data['slug']) && $this->getBySlug($data['slug'])['id'] != $courseId) {
                $data['slug'] .= '-' . time();
            }
        }
        
        // Update course
        $result = $this->db->update($this->table, $data, 'id = ?', [$courseId]);
        
        if ($result) {
            $this->logActivity(getCurrentUserId(), 'course_updated', "Course '{$course['title']}' updated", 'course', $courseId);
        }
        
        return $result;
    }
    
    /**
     * Get course by ID
     */
    public function getById($id) {
        $sql = "SELECT c.*, cat.name as category_name, cat.slug as category_slug,
                       u.first_name, u.last_name, u.username as instructor_username,
                       (SELECT AVG(rating) FROM course_reviews WHERE course_id = c.id) as avg_rating,
                       (SELECT COUNT(*) FROM course_reviews WHERE course_id = c.id) as review_count
                FROM {$this->table} c
                LEFT JOIN categories cat ON c.category_id = cat.id
                LEFT JOIN users u ON c.instructor_id = u.id
                WHERE c.id = ?";
        
        return $this->db->get($sql, [$id]);
    }
    
    /**
     * Get course by slug
     */
    public function getBySlug($slug) {
        return $this->db->get("SELECT * FROM {$this->table} WHERE slug = ?", [$slug]);
    }
    
    /**
     * Get courses with filters
     */
    public function getCourses($filters = [], $limit = 20, $offset = 0) {
        $where = ["c.status = 'published'"];
        $params = [];
        
        // Category filter
        if (!empty($filters['category_id'])) {
            $where[] = "c.category_id = ?";
            $params[] = $filters['category_id'];
        }
        
        // Region filter
        if (!empty($filters['region'])) {
            $where[] = "(c.region = ? OR c.region = 'global')";
            $params[] = $filters['region'];
        }
        
        // Level filter
        if (!empty($filters['level'])) {
            $where[] = "c.level = ?";
            $params[] = $filters['level'];
        }
        
        // Price filter
        if (isset($filters['free_only']) && $filters['free_only']) {
            $where[] = "c.price = 0";
        }
        
        // Search filter (extended to instructor and category)
        if (!empty($filters['search'])) {
            $where[] = "(c.title LIKE ? OR c.description LIKE ? OR c.short_description LIKE ? OR u.first_name LIKE ? OR u.last_name LIKE ? OR cat.name LIKE ?)";
            $searchTerm = "%{$filters['search']}%";
            // title, description, short_description, instructor first, instructor last, category
            $params[] = $searchTerm;
            $params[] = $searchTerm;
            $params[] = $searchTerm;
            $params[] = $searchTerm;
            $params[] = $searchTerm;
            $params[] = $searchTerm;
        }
        
        // Featured filter
        if (!empty($filters['featured'])) {
            $where[] = "c.featured = 1";
        }
        
        $whereClause = implode(' AND ', $where);
        
        // Order by
        $orderBy = "c.sort_order ASC, c.created_at DESC";
        if (!empty($filters['sort'])) {
            switch ($filters['sort']) {
                case 'popular':
                    $orderBy = "c.enrollment_count DESC";
                    break;
                case 'rating':
                    $orderBy = "c.rating DESC";
                    break;
                case 'price_low':
                    $orderBy = "c.price ASC";
                    break;
                case 'price_high':
                    $orderBy = "c.price DESC";
                    break;
                case 'newest':
                    $orderBy = "c.created_at DESC";
                    break;
            }
        }
        
        $sql = "SELECT c.*, cat.name as category_name, cat.slug as category_slug,
                       u.first_name, u.last_name, u.username as instructor_username
                FROM {$this->table} c
                LEFT JOIN categories cat ON c.category_id = cat.id
                LEFT JOIN users u ON c.instructor_id = u.id
                WHERE {$whereClause}
                ORDER BY {$orderBy}
                LIMIT ? OFFSET ?";
        
        $params[] = $limit;
        $params[] = $offset;
        
        return $this->db->getAll($sql, $params);
    }
    
    /**
     * Count courses matching filters (used for pagination)
     */
    public function countCourses($filters = []) {
        $where = ["c.status = 'published'"];
        $params = [];

        if (!empty($filters['category_id'])) {
            $where[] = "c.category_id = ?";
            $params[] = $filters['category_id'];
        }

        if (!empty($filters['region'])) {
            $where[] = "(c.region = ? OR c.region = 'global')";
            $params[] = $filters['region'];
        }

        if (!empty($filters['level'])) {
            $where[] = "c.level = ?";
            $params[] = $filters['level'];
        }

        if (isset($filters['free_only']) && $filters['free_only']) {
            $where[] = "c.price = 0";
        }

        if (!empty($filters['search'])) {
            $where[] = "(c.title LIKE ? OR c.description LIKE ? OR c.short_description LIKE ? OR u.first_name LIKE ? OR u.last_name LIKE ? OR cat.name LIKE ?)";
            $searchTerm = "%{$filters['search']}%";
            $params[] = $searchTerm;
            $params[] = $searchTerm;
            $params[] = $searchTerm;
            $params[] = $searchTerm;
            $params[] = $searchTerm;
            $params[] = $searchTerm;
        }

        $whereClause = implode(' AND ', $where);

        $sql = "SELECT COUNT(*) as cnt FROM {$this->table} c
                LEFT JOIN categories cat ON c.category_id = cat.id
                LEFT JOIN users u ON c.instructor_id = u.id
                WHERE {$whereClause}";

        $row = $this->db->get($sql, $params);
        return (int)($row['cnt'] ?? 0);
    }
    
    /**
     * Get instructor courses
     */
    public function getInstructorCourses($instructorId, $status = null) {
        $where = ["c.instructor_id = ?"];
        $params = [$instructorId];

        if ($status) {
            $where[] = "c.status = ?";
            $params[] = $status;
        }

        $whereClause = implode(' AND ', $where);

        $sql = "SELECT c.*, cat.name as category_name, cat.slug as category_slug,
                       u.first_name, u.last_name, u.username as instructor_username
                FROM {$this->table} c
                LEFT JOIN categories cat ON c.category_id = cat.id
                LEFT JOIN users u ON c.instructor_id = u.id
                WHERE {$whereClause}
                ORDER BY c.created_at DESC";

        return $this->db->getAll($sql, $params);
    }
    
    /**
     * Enroll student in course
     */
    public function enroll($courseId, $studentId, $paymentData = []) {
        // Check if course exists
        $course = $this->getById($courseId);
        if (!$course) {
            throw new Exception("Course not found");
        }
        
        // Check if already enrolled
        if ($this->isEnrolled($courseId, $studentId)) {
            throw new Exception("Already enrolled in this course");
        }
        
        // Check course capacity
        if ($course['max_students'] && $course['enrollment_count'] >= $course['max_students']) {
            throw new Exception("Course is full");
        }
        
        // Check regional access
        if (!$this->canAccessCourse($courseId, $studentId)) {
            throw new Exception("Course not available in your region");
        }
        
        // Resolve cohort for this enrollment if cohorts are defined
        $cohortId = null;
        try {
            $region = $_SESSION['region'] ?? ($course['region'] ?? 'usa');
            $cohortModel = new Cohort();
            $cohort = $cohortModel->findOpenCohortForEnrollment($courseId, $region);
            if ($cohort && !empty($cohort['id'])) {
                $cohortId = (int)$cohort['id'];
            }
        } catch (Exception $e) {
            // If cohorts are not available or any error occurs, fall back to enrollment without cohort
        }

        // Create enrollment
        $enrollmentData = [
            'course_id' => $courseId,
            'student_id' => $studentId,
            'enrollment_date' => formatDate(),
            'status' => 'active',
            'payment_status' => $paymentData['status'] ?? 'pending',
            'payment_amount' => $paymentData['amount'] ?? $course['price'],
            'payment_currency' => $paymentData['currency'] ?? $course['currency'],
            'payment_id' => $paymentData['payment_id'] ?? null
        ];

        if ($cohortId !== null) {
            $enrollmentData['cohort_id'] = $cohortId;
        }
        
        $enrollmentId = $this->db->insert('course_enrollments', $enrollmentData);
        
        if (!$enrollmentId) {
            throw new Exception("Failed to enroll in course");
        }
        
        // Update course enrollment count
        $this->db->query(
            "UPDATE {$this->table} SET enrollment_count = enrollment_count + 1 WHERE id = ?",
            [$courseId]
        );
        
        // Log activity
        $this->logActivity($studentId, 'course_enrolled', "Enrolled in course '{$course['title']}'", 'course', $courseId);
        
        // Send enrollment notification
        $this->sendEnrollmentNotification($studentId, $course);
        
        return $enrollmentId;
    }
    
    /**
     * Check if student is enrolled
     */
    public function isEnrolled($courseId, $studentId) {
        $enrollment = $this->db->get(
            "SELECT id FROM course_enrollments WHERE course_id = ? AND student_id = ? AND status = 'active'",
            [$courseId, $studentId]
        );
        
        return (bool)$enrollment;
    }
    
    /**
     * Get student enrollments
     */
    public function getStudentEnrollments($studentId, $status = 'active') {
        $sql = "SELECT ce.*, c.title, c.slug, c.thumbnail, c.instructor_id,
                       u.first_name, u.last_name,
                       (SELECT COUNT(*) FROM course_modules WHERE course_id = c.id) as module_count,
                       (SELECT COUNT(*) FROM lesson_progress lp 
                        JOIN course_lessons cl ON lp.lesson_id = cl.id 
                        WHERE lp.enrollment_id = ce.id AND lp.status = 'completed') as completed_lessons
                FROM course_enrollments ce
                JOIN {$this->table} c ON ce.course_id = c.id
                JOIN users u ON c.instructor_id = u.id
                WHERE ce.student_id = ? AND ce.status = ?
                ORDER BY ce.enrollment_date DESC";
        
        return $this->db->getAll($sql, [$studentId, $status]);
    }
    
    /**
     * Update course progress
     */
    public function updateProgress($enrollmentId, $lessonId, $progressData) {
        // Get or create lesson progress
        $progress = $this->db->get(
            "SELECT * FROM lesson_progress WHERE enrollment_id = ? AND lesson_id = ?",
            [$enrollmentId, $lessonId]
        );
        
        if ($progress) {
            // Update existing progress
            $this->db->update('lesson_progress', $progressData, 'id = ?', [$progress['id']]);
        } else {
            // Create new progress record
            $progressData['enrollment_id'] = $enrollmentId;
            $progressData['lesson_id'] = $lessonId;
            $progressData['student_id'] = $this->getEnrollmentStudentId($enrollmentId);
            $this->db->insert('lesson_progress', $progressData);
        }
        
        // Update overall enrollment progress
        $this->updateEnrollmentProgress($enrollmentId);
    }
    
    /**
     * Get course modules
     */
    public function getModules($courseId) {
        return $this->db->getAll(
            "SELECT * FROM course_modules WHERE course_id = ? ORDER BY sort_order ASC",
            [$courseId]
        );
    }

    /**
     * Add a module to a course
     */
    public function addModule($courseId, $data) {
        $data['course_id'] = $courseId;
        $data['created_at'] = formatDate();
        $data['updated_at'] = formatDate();
        return $this->db->insert('course_modules', $data);
    }

    /**
     * Update an existing module
     */
    public function updateModule($moduleId, $data) {
        $data['updated_at'] = formatDate();
        return $this->db->update('course_modules', $data, 'id = ?', [$moduleId]);
    }

    /**
     * Delete a module (and cascade delete lessons)
     */
    public function deleteModule($moduleId) {
        // The DB schema has FK cascade on course_modules -> course_lessons
        return $this->db->query("DELETE FROM course_modules WHERE id = ?", [$moduleId]);
    }
    
    /**
     * Get course lessons
     */
    public function getLessons($courseId, $moduleId = null) {
        $where = "course_id = ?";
        $params = [$courseId];
        
        if ($moduleId) {
            $where .= " AND module_id = ?";
            $params[] = $moduleId;
        }
        
        return $this->db->getAll(
            "SELECT * FROM course_lessons WHERE {$where} ORDER BY sort_order ASC",
            $params
        );
    }
    
    /**
     * Get lesson by ID
     */
    public function getLesson($lessonId) {
        return $this->db->get(
            "SELECT cl.*, cm.title as module_title, c.title as course_title, c.slug as course_slug
             FROM course_lessons cl
             JOIN course_modules cm ON cl.module_id = cm.id
             JOIN {$this->table} c ON cl.course_id = c.id
             WHERE cl.id = ?",
            [$lessonId]
        );
    }
    
    /**
     * Check if user can access course
     */
    public function canAccessCourse($courseId, $userId) {
        $course = $this->getById($courseId);
        $user = $this->db->get("SELECT region FROM users WHERE id = ?", [$userId]);
        
        if (!$course || !$user) {
            return false;
        }
        
        // Global courses are accessible to everyone
        if ($course['region'] === 'global') {
            return true;
        }
        
        // Check regional access
        if (FEATURE_GEOLOCATION && $_ENV['enforce_region_access']) {
            return $course['region'] === $user['region'];
        }
        
        return true;
    }
    
    /**
     * Check if user can edit course
     */
    public function canEditCourse($courseId) {
        $user = getCurrentUser();
        if (!$user) {
            return false;
        }
        
        // Determine current role from session (authoritative)
        $currentRole = $_SESSION['role'] ?? null;
        
        // Super admin can edit any course
        if ($currentRole === 'super_admin') {
            return true;
        }
        
        // Course instructor can edit their own courses
        $course = $this->getById($courseId);
        if ($course && $course['instructor_id'] == $user['id']) {
            return true;
        }
        
        // Admin can edit courses in their region
        if ($currentRole === 'admin' && $course['region'] === ($user['region'] ?? null)) {
            return true;
        }
        
        return false;
    }
    
    /**
     * Generate URL-friendly slug
     */
    private function generateSlug($title) {
        $slug = strtolower($title);
        $slug = preg_replace('/[^a-z0-9\s-]/', '', $slug);
        $slug = preg_replace('/[\s-]+/', '-', $slug);
        $slug = trim($slug, '-');
        return $slug;
    }
    
    /**
     * Update enrollment progress
     */
    private function updateEnrollmentProgress($enrollmentId) {
        // Get total lessons and completed lessons
        $stats = $this->db->get(
            "SELECT COUNT(*) as total_lessons,
                    SUM(CASE WHEN lp.status = 'completed' THEN 1 ELSE 0 END) as completed_lessons
             FROM course_lessons cl
             LEFT JOIN lesson_progress lp ON cl.id = lp.lesson_id AND lp.enrollment_id = ?
             WHERE cl.course_id = (SELECT course_id FROM course_enrollments WHERE id = ?)",
            [$enrollmentId, $enrollmentId]
        );
        
        if ($stats['total_lessons'] > 0) {
            $progress = ($stats['completed_lessons'] / $stats['total_lessons']) * 100;
            
            // Check if course is completed
            $status = ($progress >= 100) ? 'completed' : 'active';
            $completionDate = ($progress >= 100) ? formatDate() : null;
            
            $this->db->update('course_enrollments', [
                'progress_percentage' => $progress,
                'status' => $status,
                'completion_date' => $completionDate
            ], 'id = ?', [$enrollmentId]);
            
            // Issue certificate if course is completed and certification is available
            if ($progress >= 100) {
                $this->issueCertificate($enrollmentId);
            }
        }
    }
    
    /**
     * Issue certificate
     */
    private function issueCertificate($enrollmentId) {
        $enrollment = $this->db->get(
            "SELECT ce.*, c.title as course_name, c.certification_available
             FROM course_enrollments ce
             JOIN {$this->table} c ON ce.course_id = c.id
             WHERE ce.id = ?",
            [$enrollmentId]
        );
        
        if ($enrollment && $enrollment['certification_available'] && !$enrollment['certificate_issued']) {
            // Generate certificate
            $certificateId = 'CERT-' . strtoupper(generateToken(8));
            $certificateNumber = 'ST3-' . date('Y') . '-' . str_pad($enrollmentId, 6, '0', STR_PAD_LEFT);
            
            $this->db->insert('certificates', [
                'student_id' => $enrollment['student_id'],
                'course_id' => $enrollment['course_id'],
                'enrollment_id' => $enrollmentId,
                'certificate_id' => $certificateId,
                'certificate_number' => $certificateNumber,
                'student_name' => $this->getStudentName($enrollment['student_id']),
                'course_name' => $enrollment['course_name'],
                'completion_date' => date('Y-m-d', strtotime($enrollment['completion_date'])),
                'issue_date' => formatDate()
            ]);
            
            // Update enrollment
            $this->db->update('course_enrollments', [
                'certificate_issued' => 1,
                'certificate_id' => $certificateId
            ], 'id = ?', [$enrollmentId]);
        }
    }
    
    /**
     * Get student name
     */
    private function getStudentName($studentId) {
        $student = $this->db->get(
            "SELECT first_name, last_name FROM users WHERE id = ?",
            [$studentId]
        );
        
        return $student ? $student['first_name'] . ' ' . $student['last_name'] : 'Unknown';
    }
    
    /**
     * Get enrollment student ID
     */
    private function getEnrollmentStudentId($enrollmentId) {
        $enrollment = $this->db->get(
            "SELECT student_id FROM course_enrollments WHERE id = ?",
            [$enrollmentId]
        );
        
        return $enrollment ? $enrollment['student_id'] : null;
    }
    
    /**
     * Send enrollment notification
     */
    private function sendEnrollmentNotification($studentId, $course) {
        $student = $this->db->get("SELECT email, first_name FROM users WHERE id = ?", [$studentId]);
        
        if ($student) {
            $subject = "Enrollment Confirmation - {$course['title']}";
            $message = "
                <h2>Enrollment Confirmed!</h2>
                <p>Dear {$student['first_name']},</p>
                <p>You have been successfully enrolled in the course: <strong>{$course['title']}</strong></p>
                <p>You can now access the course content from your dashboard.</p>
                <p><a href='" . APP_URL . "/lms/dashboard.php'>Go to Dashboard</a></p>
            ";
            
            sendEmail($student['email'], $subject, $message);
        }
    }
    
    /**
     * Log activity
     */
    private function logActivity($userId, $action, $description, $resourceType = null, $resourceId = null) {
        $this->db->insert('activity_logs', [
            'user_id' => $userId,
            'action' => $action,
            'description' => $description,
            'resource_type' => $resourceType,
            'resource_id' => $resourceId,
            'ip_address' => getClientIP(),
            'user_agent' => getUserAgent(),
            'region' => $_SESSION['region'] ?? DEFAULT_REGION
        ]);
    }
    
    /**
     * Get course statistics
     */
    public function getCourseStats($courseId) {
        $stats = [];
        
        // Enrollment stats
        $enrollments = $this->db->get(
            "SELECT COUNT(*) as total,
                    SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
                    AVG(progress_percentage) as avg_progress
             FROM course_enrollments 
             WHERE course_id = ?",
            [$courseId]
        );
        
        $stats['enrollments'] = $enrollments;
        
        // Lesson stats
        $lessons = $this->db->get(
            "SELECT COUNT(*) as total FROM course_lessons WHERE course_id = ?",
            [$courseId]
        );
        
        $stats['lessons'] = $lessons['total'];
        
        // Revenue stats
        $revenue = $this->db->get(
            "SELECT SUM(payment_amount) as total FROM course_enrollments 
             WHERE course_id = ? AND payment_status = 'paid'",
            [$courseId]
        );
        
        $stats['revenue'] = $revenue['total'] ?: 0;
        
        return $stats;
    }
    
    /**
     * Get popular courses
     */
    public function getPopularCourses($limit = 10, $region = null) {
        $where = "c.status = 'published'";
        $params = [];
        
        if ($region) {
            $where .= " AND (c.region = ? OR c.region = 'global')";
            $params[] = $region;
        }
        
        return $this->db->getAll(
            "SELECT c.*, cat.name as category_name,
                   u.first_name, u.last_name
            FROM {$this->table} c
            LEFT JOIN categories cat ON c.category_id = cat.id
            LEFT JOIN users u ON c.instructor_id = u.id
            WHERE {$where}
            ORDER BY c.enrollment_count DESC, c.rating DESC
            LIMIT ?",
            array_merge($params, [$limit])
        );
    }
    
    /**
     * Get featured courses
     */
    public function getFeaturedCourses($limit = 6, $region = null) {
        $where = "c.status = 'published' AND c.featured = 1";
        $params = [];
        
        if ($region) {
            $where .= " AND (c.region = ? OR c.region = 'global')";
            $params[] = $region;
        }
        
        return $this->db->getAll(
            "SELECT c.*, cat.name as category_name,
                   u.first_name, u.last_name
            FROM {$this->table} c
            LEFT JOIN categories cat ON c.category_id = cat.id
            LEFT JOIN users u ON c.instructor_id = u.id
            WHERE {$where}
            ORDER BY c.sort_order ASC, c.created_at DESC
            LIMIT ?",
            array_merge($params, [$limit])
        );
    }
}
?>
