import { Request, Response, NextFunction } from 'express';
import { body, param, validationResult } from 'express-validator';
import { ensureJsonExtension } from '../../utils/fileManagement.js';
import sanitize from 'sanitize-filename';

/**
 * @description Validates request for a new project.
 */
export const validateNewProject = [
  body('title').optional().isString().trim(),
  body('description').optional().isString().trim(),
  body('publicUrl').optional().isString().trim(),
  body('publicInfo').optional().isString().trim(),
  body('backstageUrl').optional().isString().trim(),
  body('backstageInfo').optional().isString().trim(),
  body('endMessage').optional().isString().trim(),

  (req: Request, res: Response, next: NextFunction) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
    next();
  },
];

/**
 * @description Validates request for a quick project.
 */
export const validateQuickProject = [
  // Project fields
  body('project.title').isString().trim(),

  // Settings fields
  body('settings.timeFormat').optional().isIn(['12', '24']),
  body('settings.language').optional().isString().trim(),

  // ViewSettings fields
  body('viewSettings.freezeEnd').optional().isBoolean(),
  body('viewSettings.endMessage').optional().isString().trim(),

  (req: Request, res: Response, next: NextFunction) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
    next();
  },
];

/**
 * @description Validates request for pathing data in the project.
 */
export const validatePatchProject = [
  // Custom validator to ensure the body is not empty
  (req: Request, res: Response, next: NextFunction) => {
    if (Object.keys(req.body).length === 0) {
      return res.status(422).json({ errors: [{ msg: 'Request body cannot be empty' }] });
    }
    next();
  },

  body('rundown').isArray().optional({ nullable: false }),
  body('project').isObject().optional({ nullable: false }),
  body('settings').isObject().optional({ nullable: false }),
  body('viewSettings').isObject().optional({ nullable: false }),
  body('urlPresets').isArray().optional({ nullable: false }),
  body('customFields').isObject().optional({ nullable: false }),
  body('osc').isObject().optional({ nullable: false }),
  body('http').isObject().optional({ nullable: false }),

  (req: Request, res: Response, next: NextFunction) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
    next();
  },
];

/**
 * @description Validates request with newFilename in the body.
 */
export const validateNewFilenameBody = [
  body('newFilename')
    .exists()
    .isString()
    .trim()
    .customSanitizer((input: string) => sanitize(input))
    .withMessage('Failed to sanitize the filename')
    .notEmpty()
    .withMessage('Filename was empty or contained only invalid characters')
    .customSanitizer((input: string) => ensureJsonExtension(input)),

  (req: Request, res: Response, next: NextFunction) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(422).json({ errors: errors.array() });
    }

    next();
  },
];

/**
 * @description Validates request with filename in the body.
 */
export const validateFilenameBody = [
  body('filename')
    .exists()
    .isString()
    .trim()
    .customSanitizer((input: string) => sanitize(input))
    .withMessage('Failed to sanitize the filename')
    .notEmpty()
    .withMessage('Filename was empty or contained only invalid characters')
    .customSanitizer((input: string) => ensureJsonExtension(input)),

  (req: Request, res: Response, next: NextFunction) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(422).json({ errors: errors.array() });
    }

    next();
  },
];

/**
 * @description Validates request with filename in the params.
 */
export const validateFilenameParam = [
  param('filename')
    .exists()
    .isString()
    .trim()
    .customSanitizer((input: string) => sanitize(input))
    .withMessage('Failed to sanitize the filename')
    .notEmpty()
    .withMessage('Filename was empty or contained only invalid characters')
    .customSanitizer((input: string) => ensureJsonExtension(input)),

  (req: Request, res: Response, next: NextFunction) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(422).json({ errors: errors.array() });
    }

    next();
  },
];
