"use strict";
/*
 * @adonisjs/validator
 *
 * (c) Harminder Virk <virk@adonisjs.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.validate = exports.compile = void 0;
const luxon_1 = require("luxon");
const helpers_1 = require("../../../Validator/helpers");
/**
 * Returns a luxon date time instance based upon the unit, duration and operator
 */
function getDateTime(operator, { unit, duration }) {
    if (operator === '>' || operator === '>=') {
        return luxon_1.DateTime.local().plus({ [unit]: duration });
    }
    return luxon_1.DateTime.local().minus({ [unit]: duration });
}
/**
 * Returns a luxon date time instance based upon the unit, duration and operator
 */
function compareDateTime(lhs, rhs, operator, options) {
    if (options && options.hasDayDuration) {
        if (operator === '>') {
            return lhs.startOf('day') > rhs.startOf('day');
        }
        else if (operator === '>=') {
            return lhs.startOf('day') >= rhs.startOf('day');
        }
        else if (operator === '<') {
            return lhs.startOf('day') < rhs.startOf('day');
        }
        else if (operator === '<=') {
            return lhs.startOf('day') <= rhs.startOf('day');
        }
    }
    if (operator === '>') {
        return lhs > rhs;
    }
    else if (operator === '>=') {
        return lhs >= rhs;
    }
    else if (operator === '<') {
        return lhs < rhs;
    }
    else if (operator === '<=') {
        return lhs <= rhs;
    }
}
/**
 * Compiles an offset based date rule
 */
function compile(ruleName, operator, [duration, unit]) {
    /**
     * Choices are defined as a ref
     */
    if ((0, helpers_1.isRef)(duration)) {
        return {
            compiledOptions: { ref: duration.key, operator },
        };
    }
    /**
     * Converting "today" keyword to offset
     */
    if (duration === 'today') {
        return {
            compiledOptions: {
                operator,
                offset: {
                    duration: 0,
                    unit: 'days',
                    hasDayDuration: true,
                },
            },
        };
    }
    /**
     * Converting "tomorrow", "yesterday" keywords to offset
     */
    if (['tomorrow', 'yesterday'].includes(duration)) {
        return {
            compiledOptions: {
                operator,
                offset: {
                    duration: 1,
                    unit: 'days',
                    hasDayDuration: true,
                },
            },
        };
    }
    /**
     * Ensure value is an array or a ref
     */
    if (!duration || !unit) {
        throw new Error(`"${ruleName}": expects a date offset "duration" and "unit" or a "ref"`);
    }
    /**
     * Ensure interval is a valid number
     */
    if (typeof duration !== 'number') {
        throw new Error(`"${ruleName}": expects "duration" to be a number`);
    }
    return {
        compiledOptions: {
            operator,
            offset: { duration, unit, hasDayDuration: ['day', 'days'].includes(unit) },
        },
    };
}
exports.compile = compile;
/**
 * Validates offset based date rules
 */
function validate(ruleName, errorMessage, value, compiledOptions, { errorReporter, pointer, arrayExpressionPointer, refs }) {
    let comparisonDate;
    /**
     * Do not run validation when original value is not a dateTime instance.
     */
    if (luxon_1.DateTime.isDateTime(value) === false) {
        return;
    }
    /**
     * Resolve datetime to compare against
     */
    if (compiledOptions.ref) {
        comparisonDate = refs[compiledOptions.ref].value;
    }
    else if (compiledOptions.offset) {
        comparisonDate = getDateTime(compiledOptions.operator, compiledOptions.offset);
    }
    (0, helpers_1.enforceDateTime)(comparisonDate, `"${ruleName}": expects "refs.${compiledOptions.ref}" to be an instance of luxon DateTime object`);
    if (!compareDateTime(value, comparisonDate, compiledOptions.operator, compiledOptions.offset)) {
        errorReporter.report(pointer, ruleName, errorMessage, arrayExpressionPointer, {
            [ruleName]: comparisonDate.toISO(),
        });
    }
}
exports.validate = validate;
