/**
 * Module Controller
 *
 * HTTP request handlers for module endpoints
 */

import { Request, Response } from 'express';
import { moduleService } from './module.service';
import { asyncHandler } from '../../shared/middleware/validation.middleware';
import { ValidationError } from '../../shared/types';
import type { ModuleType, ExerciseDifficulty } from '@prisma/client';

// ============================================
// CONTROLLER
// ============================================

class ModuleController {
  /**
   * GET /api/modules
   * List all modules with optional filtering
   */
  listModules = asyncHandler(async (req: Request, res: Response): Promise<void> => {
    const {
      type,
      isPublished,
      difficulty,
      search,
      page = '1',
      limit = '50',
      sortBy = 'order',
      sortOrder = 'asc',
    } = req.query;

    const pageNum = parseInt(page as string, 10) || 1;
    const limitNum = parseInt(limit as string, 10) || 50;
    const skip = (pageNum - 1) * limitNum;

    const filters: any = {};
    if (type !== undefined) filters.type = type as ModuleType;
    if (isPublished !== undefined) filters.isPublished = isPublished === 'true';
    if (difficulty !== undefined) filters.difficulty = difficulty as ExerciseDifficulty;
    if (search) filters.search = search as string;

    const { modules, total } = await moduleService.listModules(filters, {
      skip,
      take: limitNum,
      orderBy: sortBy as any,
      orderDirection: sortOrder as any,
    });

    const totalPages = Math.ceil(total / limitNum);

    res.json({
      success: true,
      data: modules,
      meta: {
        pagination: {
          page: pageNum,
          limit: limitNum,
          total,
          totalPages,
          hasNext: pageNum < totalPages,
          hasPrev: pageNum > 1,
        },
      },
    });
  });

  /**
   * GET /api/modules/:id
   * Get module by ID with optional includes
   */
  getModuleById = asyncHandler(async (req: Request, res: Response): Promise<void> => {
    const { id } = req.params;
    if (!id) {
      throw new ValidationError('Module ID is required');
    }
    const {
      includeExercises = 'false',
      includeTopics = 'false',
      includeProgress = 'false',
    } = req.query;

    const module = await moduleService.getModuleById(id, {
      includeExercises: includeExercises === 'true',
      includeTopics: includeTopics === 'true',
      includeProgress: includeProgress === 'true',
      userId: req.user?.userId,
    });

    res.json({
      success: true,
      data: module,
    });
  });

  /**
   * GET /api/modules/:id/introduction
   * Get module introduction content
   */
  getModuleIntroduction = asyncHandler(async (req: Request, res: Response): Promise<void> => {
    const { id } = req.params;
    if (!id) {
      throw new ValidationError('Module ID is required');
    }

    const introduction = await moduleService.getModuleIntroduction(id);

    res.json({
      success: true,
      data: introduction,
    });
  });

  /**
   * GET /api/modules/:id/examples
   * Get module examples with LaTeX formulas
   */
  getModuleExamples = asyncHandler(async (req: Request, res: Response): Promise<void> => {
    const { id } = req.params;
    if (!id) {
      throw new ValidationError('Module ID is required');
    }

    const examples = await moduleService.getModuleExamples(id);

    res.json({
      success: true,
      data: examples,
    });
  });

  /**
   * GET /api/modules/:id/sections
   * Get module exercise sections
   */
  getModuleExerciseSections = asyncHandler(async (req: Request, res: Response): Promise<void> => {
    const { id } = req.params;
    if (!id) {
      throw new ValidationError('Module ID is required');
    }

    const sections = await moduleService.getModuleExerciseSections(id);

    res.json({
      success: true,
      data: sections,
    });
  });

  /**
   * GET /api/modules/:id/overview
   * Get module overview statistics
   */
  getModuleOverview = asyncHandler(async (req: Request, res: Response): Promise<void> => {
    const { id } = req.params;
    if (!id) {
      throw new ValidationError('Module ID is required');
    }

    const overview = await moduleService.getModuleOverview(id);

    res.json({
      success: true,
      data: overview,
    });
  });

  /**
   * GET /api/modules/:id/next
   * Get next module in sequence
   */
  getNextModule = asyncHandler(async (req: Request, res: Response): Promise<void> => {
    const { id } = req.params;
    if (!id) {
      throw new ValidationError('Module ID is required');
    }

    const nextModule = await moduleService.getNextModule(id);

    if (!nextModule) {
      res.status(404).json({
        success: false,
        error: {
          code: 'NOT_FOUND',
          message: 'No next module found',
        },
      });
      return;
    }

    res.json({
      success: true,
      data: nextModule,
    });
  });

  /**
   * GET /api/modules/:id/previous
   * Get previous module in sequence
   */
  getPreviousModule = asyncHandler(async (req: Request, res: Response): Promise<void> => {
    const { id } = req.params;
    if (!id) {
      throw new ValidationError('Module ID is required');
    }

    const previousModule = await moduleService.getPreviousModule(id);

    if (!previousModule) {
      res.status(404).json({
        success: false,
        error: {
          code: 'NOT_FOUND',
          message: 'No previous module found',
        },
      });
      return;
    }

    res.json({
      success: true,
      data: previousModule,
    });
  });

  /**
   * GET /api/modules/type/:type
   * Get modules by type
   */
  getModulesByType = asyncHandler(async (req: Request, res: Response): Promise<void> => {
    const { type } = req.params;
    if (!type) {
      throw new ValidationError('Module type is required');
    }
    const { page = '1', limit = '50' } = req.query;

    const pageNum = parseInt(page as string, 10) || 1;
    const limitNum = parseInt(limit as string, 10) || 50;
    const skip = (pageNum - 1) * limitNum;

    const { modules, total } = await moduleService.getModulesByType(
      type as ModuleType,
      {
        skip,
        take: limitNum,
      }
    );

    const totalPages = Math.ceil(total / limitNum);

    res.json({
      success: true,
      data: modules,
      meta: {
        pagination: {
          page: pageNum,
          limit: limitNum,
          total,
          totalPages,
          hasNext: pageNum < totalPages,
          hasPrev: pageNum > 1,
        },
      },
    });
  });
}

// ============================================
// EXPORT
// ============================================

export const moduleController = new ModuleController();
export default moduleController;