import path, { dirname } from 'path';
import { fileURLToPath } from 'url';

/**
 * Main backend application class, апликация - основен клас на сървърното приложение
 */
class App{
    constructor(){
        this.root = path.resolve(dirname(fileURLToPath(import.meta.url)) + '/../../');
        console.log('App root is set to', this.root);
    }

    /**
     * The plugins used by the application, списък на плъгините, използвани в приложението
     * @type {AppPlugin[]}
     */
    plugins = [];

    /**
     * Declaration of plugin usage, деклариране на употреба на плъгин
     * @param {AppPlugin} plugin The plugin to be used
     */
    async use(plugin){
        this[plugin.name] = plugin;
        plugin.app = this;
        this.plugins.push(plugin);
    }

    /**
     * Initializes the application. All plugins are initialized at this stage, инициализация на приложението, на тази стъпка се инициализират всички регистрирани плъгини
     */
    async init(){
        for (let p of this.plugins){
            console.debug('Initializing', p.name)
            if(p.init) await p.init(this);
        }
    }

    /**
     * Imports modules as plugins in the app by a given list, импортиране на списък от модули, които да бъдат регистрирани като плъгини в приложението
     * @param {Array} modules Modules to be imported, масив от модули
     */
    async importModules(modules){
        const mods = {};
        for (let m of modules){
            mods[m.name] = (await import(`../${m.path}`))[m.name];
        }
        
        for (let m of modules){
            this.use(new mods[m.name]())
        }
    }

    /**
     * Replaces a plugin, подмяна на плъгин
     * @param {AppPlugin} p Plugin to be replaced, плъгин, който да бъде подменен
     */
    async replace(p){
        let old = this[p.name];
        this.plugins[this.plugins.indexOf(old)] = p;
        this[p.name] = p;
        p.app = this;
        if(p.init) await p.init(this);
    }

    /**
     * Starts the application. All Plugins are started at this point. Стартиране на приложението и всички негови плъгини
     */
    async start(){
        for (let p of this.plugins){
            console.debug('Starting', p.name)
            if(p.start) await p.start(this);
        }
    }

    async stop(){
        for (let p of this.plugins){
            if(p.stop) {
                console.debug('Stopping', p.name)
                await p.stop(this);
            }
        }
    }
}


/* The following are pseudo in order to keep documentation aligned to the code */

/**
 * The core application plugins, основни плъгини на приложението
 */
class AppCore{
    /**
     * The configuration plugin instance, конфигурационен плъгин
     * @type Config
     */
    config = undefined;

    /**
     * The database plugin instance, плъгин към базата от данни
     * @type Db
     */
    db = undefined;

    /**
     * The web server plugin instance, уеб сървър плъгин
     * @type WebServer
     */
    webServer = undefined;
}

/**
 * The main logical part application plugins, плъгини, свързани с логическия слой на приложението - контролни класове
 */
class AppManagement {

    /**
     * Game objects manager plugin instance, управление на игрови обекти
     * @type GameObjectsManager
     */
    gameObject = undefined;

    /**
     * Games manager plugin instance, управление на игрови дефиниции
     * @type GamesManager
     */
    games = undefined;

    /**
     * Rules manager plugin instance, управление на игрови правила
     * @type RulesManager
     */
    rules = undefined;

    /**
     * Scenarios manager plugin instance, управление на игрови сценарии
     * @type ScenariosManager
     */
    scenarios = undefined;
}

/**
 * The main application controller plugin instances, основни комуникационни (гранични) класове
 */
class AppControllerApi {

    /**
     * Game objects controller plugin instance, контролер на игрови обекти
     * @type GameObjectsController
     */
    gameObjectsApi = undefined;

    /**
     * Games controller plugin instance, контролер на игрови дефиниции
     * @type GamesController
     */
    gamesApi = undefined;

    /**
     * Rules controller plugin instance, контролер на игрови правила
     * @type RulesController
     */
    rulesApi = undefined;

    /**
     * Scenarios controller plugin instance, контролер на игрови сценарии
     * @type ScenariosController
     */
    scenariosApi = undefined;

    /**
     * Asset controller plugin instance, контролер на игрови активи
     * @type AssetController
     */
    assetApi = undefined;
}

class AppConcrete {
    /**
     * Application core plugins, плъгини - ядро на приложението
     * @type AppCore
     * @memberof App
     */
    core = undefined;

    /**
     * Application management plugins, управление на приложението - логически класове
     * @type AppManagement
     * @memberof App
     */
    management = undefined;

    /**
     * Application controller API plugins, управление на граничните класове - контролери
     * @type AppControllerApi
     * @memberof App
     */
    controller = undefined
}

export default App;