/**
 * Education Controller
 * Handles education-related endpoints
 */

import { Request, Response, NextFunction } from 'express';
import { courseService } from '../services/course.service';
import { enrollmentService } from '../services/enrollment.service';
import type { CourseFilters, PaginationOptions } from '../types/education.types';

type AuthRequest = Request;

// ============================================================================
// Categories
// ============================================================================

export async function getCategories(req: Request, res: Response, next: NextFunction): Promise<void> {
  try {
    const categories = await courseService.getCategories();
    res.json({
      success: true,
      data: categories,
    });
  } catch (error) {
    next(error);
  }
}

export async function createCategory(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const { name, slug, description, icon, parentId, sortOrder } = req.body;

    if (!name) {
      res.status(400).json({
        success: false,
        error: { message: 'Category name is required', code: 'VALIDATION_ERROR' },
      });
      return;
    }

    const category = await courseService.createCategory({
      name,
      slug,
      description,
      icon,
      parentId,
      sortOrder,
    });

    res.status(201).json({
      success: true,
      data: category,
    });
  } catch (error) {
    next(error);
  }
}

// ============================================================================
// Courses
// ============================================================================

export async function getCourses(req: Request, res: Response, next: NextFunction): Promise<void> {
  try {
    const filters: CourseFilters = {
      categoryId: req.query.categoryId as string,
      level: req.query.level as CourseFilters['level'],
      status: (req.query.status as CourseFilters['status']) || 'published',
      isFree: req.query.isFree === 'true' ? true : req.query.isFree === 'false' ? false : undefined,
      search: req.query.search as string,
      minRating: req.query.minRating ? parseFloat(req.query.minRating as string) : undefined,
    };

    const pagination: PaginationOptions = {
      page: parseInt(req.query.page as string, 10) || 1,
      pageSize: Math.min(parseInt(req.query.pageSize as string, 10) || 20, 100),
      sortBy: req.query.sortBy as string,
      sortOrder: req.query.sortOrder as 'asc' | 'desc',
    };

    const result = await courseService.getCourses(filters, pagination);

    res.json({
      success: true,
      ...result,
    });
  } catch (error) {
    next(error);
  }
}

export async function getCourseById(req: Request, res: Response, next: NextFunction): Promise<void> {
  try {
    const { courseId } = req.params;

    const course = await courseService.getCourseWithDetails(courseId);
    if (!course) {
      res.status(404).json({
        success: false,
        error: { message: 'Course not found', code: 'NOT_FOUND' },
      });
      return;
    }

    res.json({
      success: true,
      data: course,
    });
  } catch (error) {
    next(error);
  }
}

export async function getCourseBySlug(req: Request, res: Response, next: NextFunction): Promise<void> {
  try {
    const { slug } = req.params;

    const course = await courseService.getCourseBySlug(slug);
    if (!course) {
      res.status(404).json({
        success: false,
        error: { message: 'Course not found', code: 'NOT_FOUND' },
      });
      return;
    }

    const courseWithDetails = await courseService.getCourseWithDetails(course.id);

    res.json({
      success: true,
      data: courseWithDetails,
    });
  } catch (error) {
    next(error);
  }
}

export async function createCourse(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const userId = req.user?.id;
    if (!userId) {
      res.status(401).json({
        success: false,
        error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
      });
      return;
    }

    const {
      title, slug, description, shortDescription, thumbnailUrl, previewVideoUrl,
      categoryId, level, tags, isFree, price, currency, requiresSubscription,
      minSubscriptionTier, durationMinutes,
    } = req.body;

    if (!title) {
      res.status(400).json({
        success: false,
        error: { message: 'Course title is required', code: 'VALIDATION_ERROR' },
      });
      return;
    }

    const course = await courseService.createCourse({
      title,
      slug,
      description,
      shortDescription,
      thumbnailUrl,
      previewVideoUrl,
      categoryId,
      level,
      tags,
      isFree,
      price,
      currency,
      requiresSubscription,
      minSubscriptionTier,
      durationMinutes,
      instructorId: userId,
    });

    res.status(201).json({
      success: true,
      data: course,
    });
  } catch (error) {
    next(error);
  }
}

export async function updateCourse(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const { courseId } = req.params;
    const updates = req.body;

    const course = await courseService.updateCourse(courseId, updates);
    if (!course) {
      res.status(404).json({
        success: false,
        error: { message: 'Course not found', code: 'NOT_FOUND' },
      });
      return;
    }

    res.json({
      success: true,
      data: course,
    });
  } catch (error) {
    next(error);
  }
}

export async function deleteCourse(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const { courseId } = req.params;

    const deleted = await courseService.deleteCourse(courseId);
    if (!deleted) {
      res.status(404).json({
        success: false,
        error: { message: 'Course not found', code: 'NOT_FOUND' },
      });
      return;
    }

    res.json({
      success: true,
      message: 'Course deleted successfully',
    });
  } catch (error) {
    next(error);
  }
}

export async function publishCourse(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const { courseId } = req.params;

    const course = await courseService.publishCourse(courseId);
    if (!course) {
      res.status(404).json({
        success: false,
        error: { message: 'Course not found', code: 'NOT_FOUND' },
      });
      return;
    }

    res.json({
      success: true,
      data: course,
      message: 'Course published successfully',
    });
  } catch (error) {
    next(error);
  }
}

export async function getPopularCourses(req: Request, res: Response, next: NextFunction): Promise<void> {
  try {
    const limit = Math.min(parseInt(req.query.limit as string, 10) || 10, 50);
    const courses = await courseService.getPopularCourses(limit);

    res.json({
      success: true,
      data: courses,
    });
  } catch (error) {
    next(error);
  }
}

export async function getNewCourses(req: Request, res: Response, next: NextFunction): Promise<void> {
  try {
    const limit = Math.min(parseInt(req.query.limit as string, 10) || 10, 50);
    const courses = await courseService.getNewCourses(limit);

    res.json({
      success: true,
      data: courses,
    });
  } catch (error) {
    next(error);
  }
}

// ============================================================================
// Modules
// ============================================================================

export async function getCourseModules(req: Request, res: Response, next: NextFunction): Promise<void> {
  try {
    const { courseId } = req.params;

    const modules = await courseService.getCourseModules(courseId);

    res.json({
      success: true,
      data: modules,
    });
  } catch (error) {
    next(error);
  }
}

export async function createModule(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const { courseId } = req.params;
    const { title, description, sortOrder, unlockAfterModuleId } = req.body;

    if (!title) {
      res.status(400).json({
        success: false,
        error: { message: 'Module title is required', code: 'VALIDATION_ERROR' },
      });
      return;
    }

    const module = await courseService.createModule({
      courseId,
      title,
      description,
      sortOrder,
      unlockAfterModuleId,
    });

    res.status(201).json({
      success: true,
      data: module,
    });
  } catch (error) {
    next(error);
  }
}

export async function deleteModule(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const { moduleId } = req.params;

    const deleted = await courseService.deleteModule(moduleId);
    if (!deleted) {
      res.status(404).json({
        success: false,
        error: { message: 'Module not found', code: 'NOT_FOUND' },
      });
      return;
    }

    res.json({
      success: true,
      message: 'Module deleted successfully',
    });
  } catch (error) {
    next(error);
  }
}

// ============================================================================
// Lessons
// ============================================================================

export async function getModuleLessons(req: Request, res: Response, next: NextFunction): Promise<void> {
  try {
    const { moduleId } = req.params;

    const lessons = await courseService.getModuleLessons(moduleId);

    res.json({
      success: true,
      data: lessons,
    });
  } catch (error) {
    next(error);
  }
}

export async function getLessonById(req: Request, res: Response, next: NextFunction): Promise<void> {
  try {
    const { lessonId } = req.params;

    const lesson = await courseService.getLessonById(lessonId);
    if (!lesson) {
      res.status(404).json({
        success: false,
        error: { message: 'Lesson not found', code: 'NOT_FOUND' },
      });
      return;
    }

    res.json({
      success: true,
      data: lesson,
    });
  } catch (error) {
    next(error);
  }
}

export async function createLesson(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const { moduleId } = req.params;
    const {
      courseId, title, slug, contentType, videoUrl, videoDurationSeconds,
      videoProvider, contentMarkdown, resources, sortOrder, isPreview,
    } = req.body;

    if (!title || !courseId) {
      res.status(400).json({
        success: false,
        error: { message: 'Title and courseId are required', code: 'VALIDATION_ERROR' },
      });
      return;
    }

    const lesson = await courseService.createLesson({
      moduleId,
      courseId,
      title,
      slug,
      contentType,
      videoUrl,
      videoDurationSeconds,
      videoProvider,
      contentMarkdown,
      resources,
      sortOrder,
      isPreview,
    });

    res.status(201).json({
      success: true,
      data: lesson,
    });
  } catch (error) {
    next(error);
  }
}

export async function deleteLesson(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const { lessonId } = req.params;

    const deleted = await courseService.deleteLesson(lessonId);
    if (!deleted) {
      res.status(404).json({
        success: false,
        error: { message: 'Lesson not found', code: 'NOT_FOUND' },
      });
      return;
    }

    res.json({
      success: true,
      message: 'Lesson deleted successfully',
    });
  } catch (error) {
    next(error);
  }
}

// ============================================================================
// Enrollments
// ============================================================================

export async function getMyEnrollments(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const userId = req.user?.id;
    if (!userId) {
      res.status(401).json({
        success: false,
        error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
      });
      return;
    }

    const enrollments = await enrollmentService.getUserEnrollments(userId);

    res.json({
      success: true,
      data: enrollments,
    });
  } catch (error) {
    next(error);
  }
}

export async function enrollInCourse(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const userId = req.user?.id;
    if (!userId) {
      res.status(401).json({
        success: false,
        error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
      });
      return;
    }

    const { courseId } = req.params;

    // Check if course exists and is free or user has purchased
    const course = await courseService.getCourseById(courseId);
    if (!course) {
      res.status(404).json({
        success: false,
        error: { message: 'Course not found', code: 'NOT_FOUND' },
      });
      return;
    }

    if (!course.isFree) {
      res.status(403).json({
        success: false,
        error: { message: 'Payment required for this course', code: 'PAYMENT_REQUIRED' },
      });
      return;
    }

    const enrollment = await enrollmentService.createEnrollment({
      userId,
      courseId,
    });

    res.status(201).json({
      success: true,
      data: enrollment,
      message: 'Successfully enrolled in course',
    });
  } catch (error) {
    if ((error as Error).message === 'Already enrolled in this course') {
      res.status(409).json({
        success: false,
        error: { message: 'Already enrolled in this course', code: 'ALREADY_ENROLLED' },
      });
      return;
    }
    next(error);
  }
}

export async function getEnrollmentStatus(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const userId = req.user?.id;
    if (!userId) {
      res.status(401).json({
        success: false,
        error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
      });
      return;
    }

    const { courseId } = req.params;

    const enrollment = await enrollmentService.getEnrollment(userId, courseId);
    const progress = enrollment
      ? await enrollmentService.getCourseProgress(userId, courseId)
      : [];

    res.json({
      success: true,
      data: {
        enrolled: !!enrollment,
        enrollment,
        lessonProgress: progress,
      },
    });
  } catch (error) {
    next(error);
  }
}

// ============================================================================
// Progress
// ============================================================================

export async function updateLessonProgress(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const userId = req.user?.id;
    if (!userId) {
      res.status(401).json({
        success: false,
        error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
      });
      return;
    }

    const { lessonId } = req.params;
    const { videoWatchedSeconds, videoCompleted, userNotes } = req.body;

    const progress = await enrollmentService.updateLessonProgress(userId, lessonId, {
      videoWatchedSeconds,
      videoCompleted,
      userNotes,
    });

    res.json({
      success: true,
      data: progress,
    });
  } catch (error) {
    if ((error as Error).message === 'Not enrolled in this course') {
      res.status(403).json({
        success: false,
        error: { message: 'You must be enrolled to track progress', code: 'NOT_ENROLLED' },
      });
      return;
    }
    next(error);
  }
}

export async function markLessonComplete(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const userId = req.user?.id;
    if (!userId) {
      res.status(401).json({
        success: false,
        error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
      });
      return;
    }

    const { lessonId } = req.params;

    const progress = await enrollmentService.markLessonComplete(userId, lessonId);

    res.json({
      success: true,
      data: progress,
      message: 'Lesson marked as complete',
    });
  } catch (error) {
    next(error);
  }
}

// ============================================================================
// User Stats
// ============================================================================

export async function getMyLearningStats(req: AuthRequest, res: Response, next: NextFunction): Promise<void> {
  try {
    const userId = req.user?.id;
    if (!userId) {
      res.status(401).json({
        success: false,
        error: { message: 'Unauthorized', code: 'UNAUTHORIZED' },
      });
      return;
    }

    const stats = await enrollmentService.getUserLearningStats(userId);

    res.json({
      success: true,
      data: stats,
    });
  } catch (error) {
    next(error);
  }
}

export async function getCourseStats(req: Request, res: Response, next: NextFunction): Promise<void> {
  try {
    const { courseId } = req.params;

    const stats = await enrollmentService.getCourseEnrollmentStats(courseId);

    res.json({
      success: true,
      data: stats,
    });
  } catch (error) {
    next(error);
  }
}
