"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractDomain = exports.handleAggregationRules = exports.handleStorageRules = exports.handleUpdateRules = exports.handleCreateRules = exports.handleBulkRules = exports.handleQueryRules = exports.handleDeleteRules = exports.handlePolicyRule = exports.handleAuthenticationRule = exports.getRulesKey = void 0;
const debug_1 = require("../utils/debug");
const database_1 = require("./database");
const rules_auth_1 = require("./rules-auth");
const rules_policy_1 = require("./rules-policy");
const rules_create_1 = require("./rules-create");
const rules_update_1 = require("./rules-update");
const rules_delete_1 = require("./rules-delete");
const rules_query_1 = require("./rules-query");
const rules_storage_1 = require("./rules-storage");
const rules_aggregate_1 = require("./rules-aggregate");
function getRulesKey(rules) {
    const defaultKeys = [];
    try {
        if (typeof rules === 'object')
            return Object.keys(rules);
        return defaultKeys;
    }
    catch (e) {
        return defaultKeys;
    }
}
exports.getRulesKey = getRulesKey;
async function withRuleResponse(errorPath, ruleResponse, fun) {
    try {
        return await fun();
    }
    catch (e) {
        (0, debug_1.devLog)(e);
        ruleResponse.errors[errorPath] = {
            message: e.message ? e.message : e.toString(),
        };
        return ruleResponse;
    }
}
async function handleAuthenticationRule(rules, ruleResponse, authAdapter, databaseAdapter, options) {
    const authRulesNames = getRulesKey(rules).filter(rule => rule.startsWith('auth'));
    if (authRulesNames.length === 0)
        return ruleResponse;
    const rule = rules[authRulesNames[0]];
    for (const action of Object.keys(rule)) {
        const data = rule[action];
        ruleResponse = await withRuleResponse(`auth.${action}`, ruleResponse, () => (0, rules_auth_1.authRule)(action, data, ruleResponse, authAdapter, databaseAdapter, rules.context, options));
    }
    return ruleResponse;
}
exports.handleAuthenticationRule = handleAuthenticationRule;
async function handlePolicyRule(rules, ruleResponse, databaseAdapter, options) {
    const policyRules = getRulesKey(rules).filter(rule => rule.startsWith('policy'));
    if (policyRules.length === 0)
        return ruleResponse;
    const policy = rules[policyRules[0]];
    for (const action of Object.keys(policy)) {
        const data = policy[action];
        ruleResponse = await withRuleResponse('policy', ruleResponse, () => (0, rules_policy_1.policyRule)(action, data, ruleResponse, databaseAdapter, rules.context, options));
    }
    return ruleResponse;
}
exports.handlePolicyRule = handlePolicyRule;
async function handleDeleteRules(rules, ruleResponse, databaseAdapter, options, transaction) {
    const deleteRules = getRulesKey(rules).filter(rule => rule.startsWith('delete'));
    if (deleteRules.length === 0)
        return ruleResponse;
    for (const rule of deleteRules) {
        const domain = extractDomain(rule, 'delete');
        const ePath = `${transaction ? 'transaction.' : ''}delete.${domain}`;
        const ruleData = rules[rule];
        ruleResponse = await withRuleResponse(ePath, ruleResponse, () => (0, rules_delete_1.handleDeleteRule)(domain, ruleData, ruleResponse, databaseAdapter, rules.context, options));
    }
    return ruleResponse;
}
exports.handleDeleteRules = handleDeleteRules;
async function handleQueryRules(rules, ruleResponse, databaseAdapter, options, transaction) {
    const queryRules = getRulesKey(rules).filter(rule => rule.startsWith('query'));
    if (queryRules.length === 0)
        return ruleResponse;
    for (const queryRule of queryRules) {
        const domain = extractDomain(queryRule, 'query');
        const ePath = `${transaction ? 'transaction.' : ''}query.${domain}`;
        const ruleData = rules[queryRule];
        ruleResponse = await withRuleResponse(ePath, ruleResponse, () => (0, rules_query_1.handleQueryRule)(domain, ruleData, ruleResponse, databaseAdapter, rules.context, options));
    }
    return ruleResponse;
}
exports.handleQueryRules = handleQueryRules;
async function handleBulkRules(rules, ruleResponse, databaseAdapter, options) {
    const transactionRules = getRulesKey(rules).filter(rule => rule === 'transaction');
    if (transactionRules.length === 0)
        return ruleResponse;
    const transactionRule = transactionRules[0];
    const transactionData = rules[transactionRule];
    const transactionOperationRules = transactionData.commit;
    const resultObject = { errors: {} };
    await (0, database_1.transaction)(databaseAdapter, async (session) => {
        await handleCreateRules(transactionOperationRules, resultObject, databaseAdapter, options, session);
        await handleUpdateRules(transactionOperationRules, resultObject, databaseAdapter, options, session);
        await handleQueryRules(transactionOperationRules, resultObject, databaseAdapter, options, session);
        await handleDeleteRules(transactionOperationRules, resultObject, databaseAdapter, options, session);
    });
    ruleResponse.transaction = { commit: { errors: resultObject.errors } };
    return ruleResponse;
}
exports.handleBulkRules = handleBulkRules;
async function handleCreateRules(rules, ruleResponse, databaseAdapter, options, transactionSession) {
    const createRules = getRulesKey(rules).filter(rule => rule.startsWith('create'));
    if (createRules.length === 0)
        return ruleResponse;
    for (const rule of createRules) {
        const domain = extractDomain(rule, 'create');
        const ePath = `${transactionSession ? 'transaction.' : ''}create.${domain}`;
        const ruleData = rules[rule];
        ruleResponse = await withRuleResponse(ePath, ruleResponse, () => (0, rules_create_1.createRule)(domain, ruleData, ruleResponse, databaseAdapter, rules.context, options));
    }
    return ruleResponse;
}
exports.handleCreateRules = handleCreateRules;
async function handleUpdateRules(rules, ruleResponse, databaseAdapter, options, transaction) {
    const updateRules = getRulesKey(rules).filter(rule => rule.startsWith('update'));
    if (updateRules.length === 0)
        return ruleResponse;
    for (const rule of updateRules) {
        const domain = extractDomain(rule, 'update');
        const ePath = `${transaction ? 'transaction.' : ''}update.${domain}`;
        const ruleData = rules[rule];
        ruleResponse = await withRuleResponse(ePath, ruleResponse, () => (0, rules_update_1.handleUpdateRule)(domain, ruleData, ruleResponse, databaseAdapter, rules.context, options));
    }
    return ruleResponse;
}
exports.handleUpdateRules = handleUpdateRules;
async function handleStorageRules(rules, ruleResponse, databaseAdapter, authAdapter, filesAdapter, options) {
    const fileRules = getRulesKey(rules).filter(rule => rule === 'files');
    if (fileRules.length === 0)
        return ruleResponse;
    const fileRule = fileRules[0];
    const ePath = 'files';
    const ruleData = rules[fileRule];
    return withRuleResponse(ePath, ruleResponse, () => (0, rules_storage_1.handleStorageRule)(ruleData, ruleResponse, filesAdapter, databaseAdapter, rules.context, options));
}
exports.handleStorageRules = handleStorageRules;
async function handleAggregationRules(rules, ruleResponse, databaseAdapter, options) {
    const aggregateRules = getRulesKey(rules).filter(rule => rule.startsWith('aggregate'));
    if (aggregateRules.length === 0)
        return ruleResponse;
    for (const aggregateRule of aggregateRules) {
        const domain = extractDomain(aggregateRule, 'aggregate');
        const ePath = `aggregate.${domain}`;
        const ruleData = rules[aggregateRule];
        ruleResponse = await withRuleResponse(ePath, ruleResponse, () => (0, rules_aggregate_1.handleAggregateRule)(domain, ruleData, ruleResponse, databaseAdapter, rules.context, options));
    }
    return ruleResponse;
}
exports.handleAggregationRules = handleAggregationRules;
function extractDomain(rule, remove) {
    if ((remove === 'create' || remove === 'query' || remove === 'update' || remove === 'index'
        || remove === 'delete' || remove === 'aggregate') && rule.startsWith(remove))
        return rule.trim().replace(remove, '');
    else
        return null;
}
exports.extractDomain = extractDomain;
