import { z } from 'zod';
import logger from './logger';

// Base schemas
const emailSchema = z.string().email('Invalid email format');
const passwordSchema = z.string().min(8, 'Password must be at least 8 characters long');
const nameSchema = z.string().min(2, 'Name must be at least 2 characters long').max(50, 'Name must be less than 50 characters');
const uuidSchema = z.string().uuid('Invalid UUID format');

// User role enum
const userRoleEnum = z.enum(['ADMIN', 'TEACHER', 'STUDENT']);

// Bot level enum
const botLevelEnum = z.enum(['A1', 'A2', 'B1', 'B2', 'C1', 'C2']);

// Auth schemas
export const registerSchema = z.object({
  name: nameSchema,
  email: emailSchema,
  password: passwordSchema,
  role: userRoleEnum.optional().default('STUDENT'),
});

export const loginSchema = z.object({
  email: emailSchema,
  password: z.string().min(1, 'Password is required'),
});

export const refreshTokenSchema = z.object({
  refreshToken: z.string().min(1, 'Refresh token is required'),
});

export const changePasswordSchema = z.object({
  currentPassword: z.string().min(1, 'Current password is required'),
  newPassword: passwordSchema,
});

// Admin set password for another user
export const adminSetPasswordSchema = z.object({
  newPassword: passwordSchema,
});

export const updateProfileSchema = z.object({
  name: nameSchema.optional(),
  profileImageUrl: z.string().url('Invalid image URL').optional(),
});

// User schemas
export const createUserSchema = z.object({
  name: nameSchema,
  email: emailSchema,
  password: passwordSchema,
  role: userRoleEnum,
  canCreateBots: z.boolean().optional(),
  canEditBots: z.boolean().optional(),
});

export const updateUserSchema = z.object({
  name: nameSchema.optional(),
  email: emailSchema.optional(),
  role: userRoleEnum.optional(),
});

export const assignBotSchema = z.object({
  studentId: uuidSchema,
  botId: uuidSchema,
});

// Schema for PATCH /api/users/:id/assign-bot endpoint
export const assignBotToUserSchema = z.object({
  botId: uuidSchema,
  notes: z.string().optional(),
});

// Schema for PATCH /api/users/:id/assign-teachers endpoint (multiple teachers)
export const assignTeachersToUserSchema = z.object({
  teacherIds: z.array(uuidSchema).min(0, 'teacherIds can be empty array to remove all'),
});

// Schema for PATCH /api/users/:id/teacher-permission (admin only, teacher permissions)
export const updateTeacherPermissionSchema = z.object({
  canCreateBots: z.boolean().optional(),
  canEditBots: z.boolean().optional(),
}).refine(
  (data) => data.canCreateBots !== undefined || data.canEditBots !== undefined,
  { message: 'At least one of canCreateBots or canEditBots must be provided' }
);

export type UpdateTeacherPermissionInput = z.infer<typeof updateTeacherPermissionSchema>;

// Bot schemas
export const createBotSchema = z.object({
  name: z.string().min(2, 'Bot name must be at least 2 characters long').max(100, 'Bot name must be less than 100 characters'),
  topic: z.string().min(5, 'Topic must be at least 5 characters long').max(200, 'Topic must be less than 200 characters'),
  level: botLevelEnum,
  imageUrl: z.string().optional(),
  agentId: z.string().min(1, 'Agent ID is required'),
  description: z.string().min(10, 'Description must be at least 10 characters long').max(500, 'Description must be less than 500 characters'),
  feedback: z.string().min(10, 'Feedback must be at least 10 characters long').max(500, 'Feedback must be less than 500 characters').optional(),
  maxUsageSeconds: z.number().int().min(0, 'Max usage must be 0 or more seconds').max(86400, 'Max usage cannot exceed 24 hours (86400 seconds)').optional(),
  isTimerEnabled: z.boolean().default(false),
}).refine((data) => {
  // If timer is enabled and maxUsageSeconds is provided, it must be >= 1 (allow 0 to represent infinite and be normalized later)
  if (data.isTimerEnabled && data.maxUsageSeconds !== undefined && data.maxUsageSeconds < 1 && data.maxUsageSeconds !== 0) {
    return false;
  }
  return true;
}, {
  message: "Max usage seconds must be at least 1 when timer is enabled",
  path: ["maxUsageSeconds"]
});

// Bot schema for file upload (without imageUrl validation)
export const createBotWithFileSchema = z.object({
  name: z.string().min(2, 'Bot name must be at least 2 characters long').max(100, 'Bot name must be less than 100 characters'),
  topic: z.string().min(5, 'Topic must be at least 5 characters long').max(200, 'Topic must be less than 200 characters'),
  level: botLevelEnum,
  agentId: z.string().min(1, 'Agent ID is required'),
  description: z.string().min(10, 'Description must be at least 10 characters long').max(500, 'Description must be less than 500 characters'),
  feedback: z.string().min(10, 'Feedback must be at least 10 characters long').max(500, 'Feedback must be less than 500 characters').optional(),
  maxUsageSeconds: z.coerce.number().int().min(0, 'Max usage must be 0 or more seconds').max(86400, 'Max usage cannot exceed 24 hours (86400 seconds)').optional(),
  isTimerEnabled: z.coerce.boolean().default(false),
}).refine((data) => {
  // If timer is enabled and maxUsageSeconds is provided, it must be >= 1 (allow 0 to represent infinite and be normalized later)
  if (data.isTimerEnabled && data.maxUsageSeconds !== undefined && data.maxUsageSeconds < 1 && data.maxUsageSeconds !== 0) {
    return false;
  }
  return true;
}, {
  message: "Max usage seconds must be at least 1 when timer is enabled",
  path: ["maxUsageSeconds"]
});

export const updateBotSchema = z.object({
  name: z.string().min(2, 'Bot name must be at least 2 characters long').max(100, 'Bot name must be less than 100 characters').optional(),
  topic: z.string().min(5, 'Topic must be at least 5 characters long').max(200, 'Topic must be less than 200 characters').optional(),
  level: botLevelEnum.optional(),
  imageUrl: z.string().optional(),
  agentId: z.string().min(1, 'Agent ID is required').optional(),
  description: z.string().min(10, 'Description must be at least 10 characters long').max(500, 'Description must be less than 500 characters').optional(),
  feedback: z.string().min(10, 'Feedback must be at least 10 characters long').max(500, 'Feedback must be less than 500 characters').optional(),
  isActive: z.coerce.boolean().optional(),
  maxUsageSeconds: z.coerce.number().int().min(0, 'Max usage must be 0 or more seconds').max(86400, 'Max usage cannot exceed 24 hours (86400 seconds)').optional(),
  isTimerEnabled: z.coerce.boolean().optional(),
}).refine((data) => {
  // If timer is enabled on update: allow absence (use existing), but if provided it must be >= 1
  if (data.isTimerEnabled && data.maxUsageSeconds !== undefined && data.maxUsageSeconds < 1) {
    return false;
  }
  return true;
}, {
  message: "Max usage seconds must be at least 1 when timer is enabled",
  path: ["maxUsageSeconds"]
});

// Pagination schema
export const paginationSchema = z.object({
  page: z.coerce.number().int().min(1, 'Page must be at least 1').default(1),
  limit: z.coerce.number().int().min(1, 'Limit must be at least 1').max(100, 'Limit must be at most 100').default(10),
});

// Filter schemas
export const userFilterSchema = z.object({
  role: userRoleEnum.optional(),
  search: z.string().optional(),
});

export const botFilterSchema = z.object({
  level: botLevelEnum.optional(),
  isActive: z.coerce.boolean().optional(),
  search: z.string().optional(),
});

// Parameter schemas
export const uuidParamSchema = z.object({
  id: uuidSchema,
});

// Type exports
export type RegisterInput = z.infer<typeof registerSchema>;
export type LoginInput = z.infer<typeof loginSchema>;
export type RefreshTokenInput = z.infer<typeof refreshTokenSchema>;
export type ChangePasswordInput = z.infer<typeof changePasswordSchema>;
export type AdminSetPasswordInput = z.infer<typeof adminSetPasswordSchema>;
export type UpdateProfileInput = z.infer<typeof updateProfileSchema>;
export type CreateUserInput = z.infer<typeof createUserSchema>;
export type UpdateUserInput = z.infer<typeof updateUserSchema>;
export type AssignBotInput = z.infer<typeof assignBotSchema>;
export type AssignBotToUserInput = z.infer<typeof assignBotToUserSchema>;
export type AssignTeachersToUserInput = z.infer<typeof assignTeachersToUserSchema>;
export type CreateBotInput = z.infer<typeof createBotSchema>;
export type CreateBotWithFileInput = z.infer<typeof createBotWithFileSchema>;
export type UpdateBotInput = z.infer<typeof updateBotSchema>;
export type PaginationInput = z.infer<typeof paginationSchema>;
export type UserFilterInput = z.infer<typeof userFilterSchema>;
export type BotFilterInput = z.infer<typeof botFilterSchema>;
export type UuidParamInput = z.infer<typeof uuidParamSchema>;

// Enhanced validation function with logging
export const validateWithLogging = <T>(
  schema: z.ZodSchema<T>,
  data: unknown,
  context: string
): T => {
  const startTime = Date.now();
  
  logger.info('🔍 Starting validation', {
    context,
    dataType: typeof data,
    isObject: typeof data === 'object',
    hasData: !!data,
    schemaType: schema.description || 'unknown'
  });

  try {
    const result = schema.parse(data);
    
    const totalTime = Date.now() - startTime;
    
    logger.info('✅ Validation successful', {
      context,
      schemaType: schema.description || 'unknown',
      dataKeys: typeof data === 'object' && data !== null ? Object.keys(data) : [],
      resultKeys: typeof result === 'object' && result !== null ? Object.keys(result) : [],
      totalTime: `${totalTime}ms`
    });

    return result;
  } catch (error) {
    const totalTime = Date.now() - startTime;
    
    if (error instanceof z.ZodError) {
      logger.warn('⚠️ Validation failed', {
        context,
        schemaType: schema.description || 'unknown',
        errorCount: error.issues.length,
        errors: error.issues.map(e => ({
          field: e.path.join('.'),
          message: e.message,
          code: e.code
        })),
        totalTime: `${totalTime}ms`
      });
    } else {
      logger.error('❌ Validation error', {
        context,
        schemaType: schema.description || 'unknown',
        error: error.message,
        totalTime: `${totalTime}ms`,
        stack: error.stack
      });
    }
    
    throw error;
  }
};

// Specific validation functions with logging
export const validateRegistration = (data: unknown): RegisterInput => {
  return validateWithLogging(registerSchema, data, 'user registration');
};

export const validateLogin = (data: unknown): LoginInput => {
  return validateWithLogging(loginSchema, data, 'user login');
};

export const validateRefreshToken = (data: unknown): RefreshTokenInput => {
  return validateWithLogging(refreshTokenSchema, data, 'token refresh');
};

export const validateChangePassword = (data: unknown): ChangePasswordInput => {
  return validateWithLogging(changePasswordSchema, data, 'password change');
};

export const validateAdminSetPassword = (data: unknown): AdminSetPasswordInput => {
  return validateWithLogging(adminSetPasswordSchema, data, 'admin set password');
};

export const validateUpdateProfile = (data: unknown): UpdateProfileInput => {
  return validateWithLogging(updateProfileSchema, data, 'profile update');
};

export const validateCreateUser = (data: unknown): CreateUserInput => {
  return validateWithLogging(createUserSchema, data, 'user creation');
};

export const validateUpdateUser = (data: unknown): UpdateUserInput => {
  return validateWithLogging(updateUserSchema, data, 'user update');
};

export const validateAssignBot = (data: unknown): AssignBotInput => {
  return validateWithLogging(assignBotSchema, data, 'bot assignment');
};

export const validateCreateBot = (data: unknown): CreateBotInput => {
  return validateWithLogging(createBotSchema, data, 'bot creation');
};

export const validateUpdateBot = (data: unknown): UpdateBotInput => {
  return validateWithLogging(updateBotSchema, data, 'bot update');
};

export const validatePagination = (data: unknown): PaginationInput => {
  return validateWithLogging(paginationSchema, data, 'pagination');
};

export const validateUserFilter = (data: unknown): UserFilterInput => {
  return validateWithLogging(userFilterSchema, data, 'user filtering');
};

export const validateBotFilter = (data: unknown): BotFilterInput => {
  return validateWithLogging(botFilterSchema, data, 'bot filtering');
};

export const validateUuidParam = (data: unknown): UuidParamInput => {
  return validateWithLogging(uuidParamSchema, data, 'UUID parameter');
};

// Enhanced safe parse function with logging
export const safeParseWithLogging = <T>(
  schema: z.ZodSchema<T>,
  data: unknown,
  context: string
): { success: true; data: T } | { success: false; errors: z.ZodError<any> } => {
  const startTime = Date.now();
  
  logger.info('🔍 Starting safe validation', {
    context,
    dataType: typeof data,
    isObject: typeof data === 'object',
    hasData: !!data,
    schemaType: schema.description || 'unknown'
  });

  const result = schema.safeParse(data);
  
  const totalTime = Date.now() - startTime;
  
  if (result.success) {
    logger.info('✅ Safe validation successful', {
      context,
      schemaType: schema.description || 'unknown',
      dataKeys: typeof data === 'object' && data !== null ? Object.keys(data) : [],
      resultKeys: typeof result.data === 'object' && result.data !== null ? Object.keys(result.data) : [],
      totalTime: `${totalTime}ms`
    });
  } else {
    logger.warn('⚠️ Safe validation failed', {
      context,
      schemaType: schema.description || 'unknown',
      errorCount: result.error.issues.length,
      errors: result.error.issues.map(e => ({
        field: e.path.join('.'),
        message: e.message,
        code: e.code
      })),
      totalTime: `${totalTime}ms`
    });
  }
  
  if (result.success) {
    return { success: true, data: result.data };
  }
  return { success: false, errors: result.error };
};

// Validation middleware for Express
export const validateRequest = <T>(schema: z.ZodSchema<T>) => {
  return (req: any, res: any, next: any) => {
    const startTime = Date.now();
    
    logger.info('🔍 Validating request', {
      path: req.path,
      method: req.method,
      schemaType: schema.description || 'unknown',
      hasBody: !!req.body,
      hasQuery: !!req.query,
      hasParams: !!req.params
    });

    try {
      let data: unknown;
      
      // Determine what to validate based on request method
      if (req.method === 'GET') {
        data = req.query;
      } else {
        data = req.body;
      }
      
      const validatedData = validateWithLogging(schema, data, `${req.method} ${req.path}`);
      
      // Attach validated data to request
      req.validatedData = validatedData;
      
      const totalTime = Date.now() - startTime;
      
      logger.info('✅ Request validation successful', {
        path: req.path,
        method: req.method,
        schemaType: schema.description || 'unknown',
        totalTime: `${totalTime}ms`
      });
      
      next();
    } catch (error) {
      const totalTime = Date.now() - startTime;
      
      logger.error('❌ Request validation failed', {
        path: req.path,
        method: req.method,
        schemaType: schema.description || 'unknown',
        error: error.message,
        totalTime: `${totalTime}ms`
      });
      
      next(error);
    }
  };
};

