const path = require('path');
const fs = require('fs');

module.exports = Self => {
    Self.remoteMethod('modelInfo', {
        description: 'Gets all models information',
        accepts: [
            {
                arg: 'ctx',
                type: 'Object',
                http: {source: 'context'}
            }
        ],
        returns: {
            type: 'Object',
            root: true
        },
        http: {
            path: `/modelInfo`,
            verb: 'GET'
        }
    });

    const modelsLocale = new Map();
    const modulesDir = path.resolve(`${process.cwd()}/modules`);
    const modules = fs.readdirSync(modulesDir);

    for (const mod of modules) {
        const modelsDir = path.join(modulesDir, mod, `back/locale`);
        if (!fs.existsSync(modelsDir)) continue;
        const models = fs.readdirSync(modelsDir);

        for (const model of models) {
            const localeDir = path.join(modelsDir, model);
            const localeFiles = fs.readdirSync(localeDir);

            let modelName = model.charAt(0).toUpperCase() + model.substring(1);
            modelName = modelName.replace(/-\w/g, match => {
                return match.charAt(1).toUpperCase();
            });

            const modelLocale = new Map();
            modelsLocale.set(modelName, modelLocale);

            for (const localeFile of localeFiles) {
                const localePath = path.join(localeDir, localeFile);

                const match = localeFile.match(/^([a-z]+)\.yml$/);
                if (!match) {
                    console.warn(`Skipping wrong model locale file: ${localeFile}`);
                    continue;
                }

                const translations = require(localePath);
                modelLocale.set(match[1], translations);
            }
        }
    }

    Self.modelInfo = async function(ctx) {
        let json = {};
        let models = Self.app.models;

        for (let modelName in models) {
            let model = models[modelName];
            let validations = model.validations;
            let jsonValidations = {};

            for (let fieldName in validations) {
                let jsonField = [];

                for (let validation of validations[fieldName]) {
                    let options = validation.options;

                    if ((options && options.async) ||
                        (validation.validation == 'custom' && !validation.isExportable))
                        continue;

                    let validationCp = Object.assign({}, validation);

                    if (validationCp.message)
                        validationCp.message = ctx.req.__(validationCp.message);

                    jsonField.push(toJson(validationCp));
                }

                jsonValidations[fieldName] = jsonField;
            }

            const modelLocale = modelsLocale.get(modelName);
            const lang = ctx.req.getLocale();
            const locale = modelLocale && modelLocale.get(lang);

            json[modelName] = {
                http: model.sharedClass.http.path,
                properties: model.definition.rawProperties,
                validations: jsonValidations,
                locale
            };
        }

        return json;
    };

    function toJson(object) {
        let json = {};

        for (let prop in object) {
            let value = object[prop];

            switch (typeof value) {
            case 'object':
                if (value instanceof RegExp)
                    json[prop] = value.source;
                break;
            case 'function':
                json[prop] = value.toString();
                break;
            default:
                json[prop] = value;
            }
        }

        return json;
    }
};