/**
 * Admin DTOs
 *
 * Validation schemas for admin endpoints using Zod
 * All schemas use .strict() to prevent mass assignment attacks
 */

import { z } from 'zod';
import { ExerciseType, ExerciseDifficulty, ModuleType, TopicType } from '@prisma/client';
import { Request, Response, NextFunction } from 'express';

// ============================================
// EXERCISE VALIDATION SCHEMAS
// ============================================

/**
 * Solution step schema
 */
const SolutionStepSchema = z.object({
  step: z.number().int().positive(),
  explanation: z.string().min(1),
  latexFormula: z.string().optional(),
});

/**
 * Multiple choice option schema
 */
const MultipleChoiceOptionSchema = z.object({
  id: z.string(),
  text: z.string().min(1),
  isCorrect: z.boolean(),
});

/**
 * Update exercise schema - strict mode prevents mass assignment
 */
export const UpdateExerciseSchema = z.object({
  statement: z.string().min(10).max(5000).optional(),
  correctAnswer: z.string().min(1).max(1000).optional(),
  solutionSteps: z.array(SolutionStepSchema).max(50).optional(),
  formulas: z.array(z.string()).optional(),
  hints: z.array(z.string().max(500)).max(10).optional(),
  difficulty: z.nativeEnum(ExerciseDifficulty).optional(),
  type: z.nativeEnum(ExerciseType).optional(),
  points: z.number().int().min(1).max(100).optional(),
  timeLimit: z.number().int().min(30).max(3600).optional(),
  order: z.number().int().min(0).optional(),
  isPublished: z.boolean().optional(),
  moduleId: z.string().uuid().optional(),
  topicId: z.string().uuid().optional(),
  multipleChoiceOptions: z.array(MultipleChoiceOptionSchema).optional(),
}).strict();

/**
 * Create exercise schema
 */
export const CreateExerciseSchema = z.object({
  statement: z.string().min(10).max(5000),
  correctAnswer: z.string().min(1).max(1000),
  solutionSteps: z.array(SolutionStepSchema).max(50).optional(),
  formulas: z.array(z.string()).optional(),
  hints: z.array(z.string().max(500)).max(10).optional(),
  difficulty: z.nativeEnum(ExerciseDifficulty),
  type: z.nativeEnum(ExerciseType),
  points: z.number().int().min(1).max(100).default(10),
  timeLimit: z.number().int().min(30).max(3600).optional(),
  order: z.number().int().min(0).optional(),
  isPublished: z.boolean().default(false),
  moduleId: z.string().uuid().optional(),
  topicId: z.string().uuid().optional(),
  multipleChoiceOptions: z.array(MultipleChoiceOptionSchema).optional(),
}).strict();

// ============================================
// MODULE VALIDATION SCHEMAS
// ============================================

/**
 * Create module schema - strict mode prevents mass assignment
 */
export const CreateModuleSchema = z.object({
  name: z.string().min(3).max(200),
  description: z.string().min(10).max(2000),
  type: z.nativeEnum(ModuleType),
  order: z.number().int().min(0),
  introduction: z.string().max(5000).optional(),
  examples: z.array(z.record(z.unknown())).optional(),
  exercisesData: z.array(z.record(z.unknown())).optional(),
  answers: z.record(z.unknown()).optional(),
}).strict();

/**
 * Update module schema (partial for updates)
 */
export const UpdateModuleSchema = z.object({
  name: z.string().min(3).max(200).optional(),
  description: z.string().min(10).max(2000).optional(),
  type: z.nativeEnum(ModuleType).optional(),
  order: z.number().int().min(0).optional(),
  introduction: z.string().max(5000).optional(),
  examples: z.array(z.record(z.unknown())).optional(),
  exercisesData: z.array(z.record(z.unknown())).optional(),
  answers: z.record(z.unknown()).optional(),
}).strict();

/**
 * Publish module schema
 */
export const PublishModuleSchema = z.object({
  isPublished: z.boolean(),
}).strict();

// ============================================
// EXERCISE GENERATION SCHEMAS
// ============================================

/**
 * Generate exercise schema - updated with strict validation
 */
export const GenerateExerciseSchema = z.object({
  topic: z.nativeEnum(TopicType),
  moduleType: z.nativeEnum(ModuleType),
  exerciseType: z.nativeEnum(ExerciseType),
  difficulty: z.nativeEnum(ExerciseDifficulty),
  count: z.number().int().min(1).max(20).default(1),
  moduleId: z.string().uuid().optional(),
  topicId: z.string().uuid().optional(),
  isPublished: z.boolean().default(false),
  customPoints: z.number().int().min(1).max(100).optional(),
  timeLimitSeconds: z.number().int().min(30).max(3600).optional(),
  context: z.string().max(2000).optional(),
}).strict();

/**
 * Regenerate exercise schema
 */
export const RegenerateExerciseSchema = z.object({
  feedback: z.string().min(1).max(2000),
}).strict();

// ============================================
// PUBLISH SCHEMAS
// ============================================

/**
 * Publish exercise schema
 */
export const PublishExerciseSchema = z.object({
  isPublished: z.boolean(),
}).strict();

// ============================================
// VALIDATION MIDDLEWARE
// ============================================

/**
 * Generic body validation middleware
 */
export function validateBody<T extends z.ZodTypeAny>(schema: T) {
  return (req: Request, res: Response, next: NextFunction): void => {
    try {
      const validated = schema.parse(req.body);
      (req as Request & { body: z.infer<T> }).body = validated;
      next();
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: {
            code: 'VALIDATION_ERROR',
            message: 'Invalid request body',
            details: error.errors.map(e => ({
              path: e.path.join('.'),
              message: e.message,
              code: e.code,
            })),
          },
        });
        return;
      }
      next(error);
    }
  };
}

/**
 * Generic query validation middleware
 */
export function validateQuery<T extends z.ZodTypeAny>(schema: T) {
  return (req: Request, res: Response, next: NextFunction): void => {
    try {
      const validated = schema.parse(req.query);
      (req as Request & { query: z.infer<T> }).query = validated;
      next();
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: {
            code: 'VALIDATION_ERROR',
            message: 'Invalid query parameters',
            details: error.errors.map(e => ({
              path: e.path.join('.'),
              message: e.message,
              code: e.code,
            })),
          },
        });
        return;
      }
      next(error);
    }
  };
}

// ============================================
// TYPE EXPORTS
// ============================================

export type UpdateExerciseDto = z.infer<typeof UpdateExerciseSchema>;
export type CreateExerciseDto = z.infer<typeof CreateExerciseSchema>;
export type CreateModuleDto = z.infer<typeof CreateModuleSchema>;
export type UpdateModuleDto = z.infer<typeof UpdateModuleSchema>;
export type GenerateExerciseDto = z.infer<typeof GenerateExerciseSchema>;
export type RegenerateExerciseDto = z.infer<typeof RegenerateExerciseSchema>;
