import { RequestHandler } from 'express';
import { isNil } from 'lodash';
import { BadRequestError } from '../../business/errors';
import { ErrorCodes } from '../../business/errors/errorCodes';
import { HumandResponse } from '../types/response';
import { OptionalPaginableVC } from '../validationClasses/paginableVC';
import { genericValidateParams } from './genericValidateParams';

export const DEFAULT_LIMIT = 10;

export const validatePageLimitPagination = (options: {
    required: boolean;
    maxLimit: number;
    defaultLimit?: number;
}): RequestHandler<any, HumandResponse, any, any> => {
    return genericValidateParams(
        (req) => req.query,
        (res: HumandResponse, output: OptionalPaginableVC) => {
            const { page, limit, pageIncludingId } = output;
            if (options.required && page == null && limit == null) {
                throw new BadRequestError('Params "page" and/or "limit" must be defined', ErrorCodes.INVALID_DATA);
            }
            let newLimit: number | undefined = undefined;
            let offset = 0;
            if (pageIncludingId && page) {
                throw new BadRequestError(`The page and pageIncludingId params cannot be send together`, ErrorCodes.INVALID_DATA);
            }
            if (!isNil(page)) {
                newLimit = limit ?? DEFAULT_LIMIT;
                offset = (page - 1) * newLimit;
            } else if (!isNil(limit)) {
                newLimit = limit;
                offset = 0;
            }
            if (newLimit && (newLimit <= 0 || newLimit > options.maxLimit)) {
                throw new BadRequestError(`The limit must be an integer between 1 and ${options.maxLimit}`, ErrorCodes.INVALID_DATA);
            }
            res.locals.limitOffsetPagination = { limit: newLimit, offset: offset, pageIncludingId };
            if (options.required) {
                res.locals.requiredLimitOffsetPagination = { limit: newLimit as number, offset: offset };
            }
        },
        OptionalPaginableVC,
    );
};
