import { isUUID } from 'class-validator';
import { NextFunction, Request } from 'express';
import { isString, toNumber, toString } from 'lodash';
import { BadRequestError } from '../../business/errors';
import { ErrorCodes } from '../../business/errors/errorCodes';
import { isNumber } from '../../infrastructure/helpers/util';
import { HumandResponse } from '../types/response';

const validatePathParam = (
    req: Request,
    res: HumandResponse,
    next: NextFunction,
    paramName: string,
    functionValidator: (param: string) => boolean,
    sanitizerFunction: (param: string) => number | string,
) => {
    if (!functionValidator(req.params[paramName])) {
        throw new BadRequestError(`Invalid ${paramName} format`, ErrorCodes.INVALID_DATA);
    }
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    res.locals[paramName] = sanitizerFunction(req.params[paramName]);
    next();
};

const isStringInAllowedValues =
    (allowedValues?: string[]) =>
    (param: string): boolean => {
        return isString(param) && (allowedValues?.includes(param) ?? true);
    };

export const validateNumberPathParam = (req: Request, res: HumandResponse, next: NextFunction, paramName: string) =>
    validatePathParam(req, res, next, paramName, isNumber, toNumber);

const validateStringPathParam = (req: Request, res: HumandResponse, next: NextFunction, paramName: string) =>
    validatePathParam(req, res, next, paramName, isString, toString);

export const validateUUIDPathParam = (req: Request, res: HumandResponse, next: NextFunction, paramName: string) =>
    validatePathParam(req, res, next, paramName, isUUID, toString);

export const validateIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void => validateNumberPathParam(req, res, next, 'id');

export const validateUserIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'userId');

export const validateGroupNamePathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateStringPathParam(req, res, next, 'groupName');

export const validateAttachmentIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'attachmentId');

export const validateAttachmentKeyPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateStringPathParam(req, res, next, 'attachmentKey');

export const validateProfileFieldUUIDPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validatePathParam(req, res, next, 'profileFieldUUID', isString, toString);

export const validateStepIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'stepId');

export const validateReviewIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'reviewId');

export const validateEditRequestIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'editRequestId');

export const validatePostIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'postId');

export const validateTemplateIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'templateId');

export const validateCommentIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'commentId');

export const validatePollIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'pollId');

export const validatePollOptionIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'pollOptionId');

export const validateTypePathParam =
    (allowedValues?: string[]) =>
    (req: Request, res: HumandResponse, next: NextFunction): void => {
        validatePathParam(req, res, next, 'type', isStringInAllowedValues(allowedValues), toString);
    };

export const validateTagPathParam = (req: Request, res: HumandResponse, next: NextFunction): void => validateStringPathParam(req, res, next, 'tag');

export const validateProgressionIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateStringPathParam(req, res, next, 'progressionId');

export const validateAnswerIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'answerId');

export const validateGroupRequestIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'groupRequestId');

export const validateRequestIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'requestId');

export const validateCriterionIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'criterionId');

export const validateCallIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateUUIDPathParam(req, res, next, 'callId');

export const validateOwnerIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'ownerId');

export const validateLiveStreamIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateUUIDPathParam(req, res, next, 'liveStreamId');

export const validateEmployeeInternalIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateStringPathParam(req, res, next, 'employeeInternalId');

export const validateExternalIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateStringPathParam(req, res, next, 'externalId');

export const validateFormIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'formId');

export const validateGroupIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'groupId');

export const validateQuestionIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'questionId');

export const validateTopicIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'topicId');

export const validateSectionIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'sectionId');

export const validateChatIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'chatId');

export const validateMessageIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'messageId');

export const validateTaskIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'taskId');

export const validateCategoryIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'categoryId');

export const validateBossIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'bossId');

export const validateCapabilityNamePathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateStringPathParam(req, res, next, 'capabilityName');

export const validateQuizIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'quizId');

export const validateEmailTypePathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateStringPathParam(req, res, next, 'emailType');

export const validateRegionIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'regionId');

export const validateModuleIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'moduleId');

export const validateFilterIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'filterId');

export const validateEventOrganizerIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateUUIDPathParam(req, res, next, 'organizerId');

export const validateNumberPathParamWith =
    <R extends HumandResponse>(paramName: string) =>
    (req: Request, res: R, next: NextFunction): void =>
        validateNumberPathParam(req, res, next, paramName);

export const validateStringPathParamWith =
    <R extends HumandResponse>(paramName: string) =>
    (req: Request, res: R, next: NextFunction): void =>
        validateStringPathParam(req, res, next, paramName);

export const validateUUIDPathParamWith =
    <R extends HumandResponse>(paramName: string) =>
    (req: Request, res: R, next: NextFunction): void =>
        validateUUIDPathParam(req, res, next, paramName);

export const validateShiftAssignedDayIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'shiftAssignedDayId');

export const validateShiftAssignedShiftIdPathParam = (req: Request, res: HumandResponse, next: NextFunction): void =>
    validateNumberPathParam(req, res, next, 'shiftAssignedShiftId');
