"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ScorecardVersion = exports.ScorecardVersionSchema = exports.ScoreBandsJoiSchema = exports.DecisionRulesJoiSchema = exports.ScorecardDefinitionJoiSchema = exports.RISK_RATINGS = exports.SCORECARD_VERSION_STATUS = exports.SCORECARD_VERSION_STATUSES = exports.SCORECARD_CRITERION_TYPE = exports.SCORECARD_CRITERION_TYPES = void 0;
const joi_1 = __importDefault(require("joi"));
const mongoose_1 = __importDefault(require("mongoose"));
const _models_1 = require("./_models");
exports.SCORECARD_CRITERION_TYPES = [
    'boolean',
    'enum',
    'number',
    'range',
    'rating',
];
exports.SCORECARD_CRITERION_TYPE = {
    BOOLEAN: 'boolean',
    ENUM: 'enum',
    NUMBER: 'number',
    RANGE: 'range',
    RATING: 'rating',
};
exports.SCORECARD_VERSION_STATUSES = [
    'draft',
    'active',
    'archived',
];
exports.SCORECARD_VERSION_STATUS = {
    DRAFT: 'draft',
    ACTIVE: 'active',
    ARCHIVED: 'archived',
};
exports.RISK_RATINGS = [
    'PASS',
    'SPECIAL_MENTION',
    'SUBSTANDARD',
    'DOUBTFUL',
];
const scoringRuleSchema = joi_1.default.object({
    score: joi_1.default.number().required(),
    // mutually exclusive conditions
    equals: joi_1.default.alternatives(joi_1.default.string(), joi_1.default.number(), joi_1.default.boolean()),
    lt: joi_1.default.number(),
    lte: joi_1.default.number(),
    gt: joi_1.default.number(),
    gte: joi_1.default.number(),
    between: joi_1.default.array().items(joi_1.default.number()).length(2),
})
    .xor('equals', 'lt', 'lte', 'gt', 'gte', 'between')
    .required();
const criterionSchema = joi_1.default.object({
    key: joi_1.default.string()
        .regex(/^[a-z][a-zA-Z0-9]*$/)
        .required(),
    label: joi_1.default.string().required(),
    type: joi_1.default.string()
        .valid(...exports.SCORECARD_CRITERION_TYPES)
        .required(),
    options: joi_1.default.when('type', {
        is: 'enum',
        then: joi_1.default.array()
            .items(joi_1.default.object({
            value: joi_1.default.string().required(),
            label: joi_1.default.string().required(),
        }))
            .min(1)
            .required(),
        otherwise: joi_1.default.forbidden(),
    }),
    min: joi_1.default.when('type', {
        is: joi_1.default.valid('number', 'range', 'rating'),
        then: joi_1.default.number().optional(),
        otherwise: joi_1.default.forbidden(),
    }),
    max: joi_1.default.when('type', {
        is: joi_1.default.valid('number', 'range', 'rating'),
        then: joi_1.default.number().optional(),
        otherwise: joi_1.default.forbidden(),
    }),
    step: joi_1.default.when('type', {
        is: joi_1.default.valid('number', 'range', 'rating'),
        then: joi_1.default.number().optional(),
        otherwise: joi_1.default.forbidden(),
    }),
    prefix: joi_1.default.when('type', {
        is: joi_1.default.valid('number', 'range', 'rating'),
        then: joi_1.default.string().optional(),
        otherwise: joi_1.default.forbidden(),
    }),
    suffix: joi_1.default.when('type', {
        is: joi_1.default.valid('number', 'range', 'rating'),
        then: joi_1.default.string().optional(),
        otherwise: joi_1.default.forbidden(),
    }),
    rules: joi_1.default.array()
        .items(scoringRuleSchema)
        .min(1)
        .required(),
});
const sectionSchema = joi_1.default.object({
    key: joi_1.default.string()
        .regex(/^[a-z][a-zA-Z0-9]*$/)
        .required(),
    label: joi_1.default.string().required(),
    order: joi_1.default.number().integer().min(1).required(),
    maxScore: joi_1.default.number().required(),
    criteria: joi_1.default.array()
        .items(criterionSchema)
        .min(1)
        .required(),
});
exports.ScorecardDefinitionJoiSchema = joi_1.default.object({
    sections: joi_1.default.array()
        .items(sectionSchema)
        .min(1)
        .required(),
}).required();
const DecisionRuleJoiSchema = joi_1.default.object({
    when: joi_1.default.object({
        key: joi_1.default.string().required(),
        equals: joi_1.default.alternatives(joi_1.default.string(), joi_1.default.number(), joi_1.default.boolean()).required(),
    }).required(),
    result: joi_1.default.string()
        .valid(...exports.RISK_RATINGS)
        .required(),
    priority: joi_1.default.number().integer().min(1).required(),
});
exports.DecisionRulesJoiSchema = joi_1.default.array()
    .items(DecisionRuleJoiSchema)
    .min(0)
    .required();
const ScoreBandJoiSchema = joi_1.default.object({
    min: joi_1.default.number().required(),
    max: joi_1.default.number().optional(),
    result: joi_1.default.string()
        .valid(...exports.RISK_RATINGS)
        .required(),
});
exports.ScoreBandsJoiSchema = joi_1.default.array()
    .items(ScoreBandJoiSchema)
    .min(1)
    .required();
const DecisionRuleSchema = new mongoose_1.default.Schema({
    when: {
        key: { type: String, required: true },
        equals: {
            type: mongoose_1.default.Schema.Types.Mixed,
            required: true,
        },
    },
    result: {
        type: String,
        enum: exports.RISK_RATINGS,
        required: true,
    },
    priority: {
        type: Number,
        required: true,
    },
}, { _id: false });
const ScoreBandSchema = new mongoose_1.default.Schema({
    min: { type: Number, required: true },
    max: { type: Number },
    result: {
        type: String,
        enum: exports.RISK_RATINGS,
        required: true,
    },
}, { _id: false });
exports.ScorecardVersionSchema = new mongoose_1.default.Schema({
    scorecardId: {
        type: mongoose_1.default.Schema.Types.ObjectId,
        ref: _models_1.MODEL_NAMES.scorecard,
        required: true,
    },
    version: {
        type: String,
        required: true,
    },
    validFrom: {
        type: Date,
        required: true,
    },
    validTo: {
        type: Date,
    },
    status: {
        type: String,
        enum: exports.SCORECARD_VERSION_STATUSES,
        required: true,
        index: true,
    },
    definition: {
        type: mongoose_1.default.Schema.Types.Mixed,
        required: true,
    },
    decisionRules: {
        type: [DecisionRuleSchema],
        required: true,
    },
    scoreBands: {
        type: [ScoreBandSchema],
        required: true,
    },
}, {
    timestamps: { createdAt: true, updatedAt: true },
    versionKey: false,
});
exports.ScorecardVersion = mongoose_1.default.model(_models_1.MODEL_NAMES.scorecardVersion, exports.ScorecardVersionSchema);
exports.ScorecardVersionSchema.index({ scorecardId: 1, version: 1 }, { unique: true });
exports.ScorecardVersionSchema.index({ scorecardId: 1, status: 1 }, { unique: true, partialFilterExpression: { status: 'active' } });
exports.ScorecardVersionSchema.pre('save', function (next) {
    if (!this.isNew && this.isModified('definition')) {
        return next(new Error('ScorecardVersion definition is immutable'));
    }
    next();
});
