import * as path from 'path';
import { getLogger } from 'omelox-logger';
import { ConsoleService, IModule, MasterAgent, MonitorAgent, MonitorCallback } from 'omelox-admin';
import { Application } from '../application';
import { KEYWORDS, ServerInfo } from '../util/constants';
import { events } from '../index';
import { MasterWatcherModule } from './masterwatcher';

let logger = getLogger('omelox', path.basename(__filename));

// 单个进程重启通知 afterStartAll 生命周期事件。
export class RestartNotifyModule implements IModule {
    app: Application;
    service: any;
    id: string;

    static moduleId = 'RestartNotifyModule';
    private readonly removedServers: { [key: string]: boolean } = {};

    private _addEvent = this.onAddServers.bind(this);
    private _removeEvent = this.onRemoveServers.bind(this);
    private _masterWatcherModule: MasterWatcherModule;

    constructor(opts: { app: Application }, consoleService: ConsoleService) {
        this.app = opts.app;
        this.service = consoleService;

    }


    // ----------------- bind methods -------------------------

    private onAddServers(servers: ServerInfo[]) {
        if (!servers || !servers.length) {
            return;
        }
        servers.forEach(val => this.onServerAdd(val));
    }

    private onRemoveServers(ids: string[]) {
        if (ids && ids.length) {
            // 避免有重复通知的问题。
            this._masterWatcherModule.watchdog.isStarted = true;
            this._masterWatcherModule.watchdog.count = -1;
            ids.forEach(val => this.onServerLeave(val));
        }

    }

    private onServerAdd(record: ServerInfo) {
        if (this.removedServers[record.id]) {
            this.removedServers[record.id] = false;
            // TOxDO notify afterStartAll
            const masterAgent = this.service.agent as MasterAgent;
            logger.warn('notify afterStartAll ', record.id);
            process.nextTick(() => {
                masterAgent.request(record.id, 'RestartNotifyModule', { action: 'afterStartCallback' }, (err, body) => {
                    logger.warn('RestartNotifyModule notify RestartNotifyModule afterStart:', record.id, err, body);
                    // 通知startOver
                    masterAgent.request(record.id, KEYWORDS.MONITOR_WATCHER, { action: 'startOver' }, (err, body) => {
                        logger.warn('RestartNotifyModule notify MONITOR_WATCHER start over:', record.id, err, body);
                    });
                });
            });
        }
    }


    private onServerLeave(id: string) {
        logger.debug('RestartNotifyModule onServerLeave: %s', id);
        if (!id) {
            logger.warn('onServerLeave receive server id is empty.');
            return;
        }
        this.removedServers[id] = true;
    }

    private afterStartCallBack: any = null;
    private afterStartCalled = false;

    afterStart() {
        logger.debug('~~ RestartNotifyModule afterStart', this.id);
        this.afterStartCalled = true;
        if (this.afterStartCallBack) {
            this.afterStartCallBack(1);
            this.afterStartCallBack = null;
        }
    }

    // ----------------- module methods -------------------------

    start(cb: () => void) {
        //    subscribeRequest(this, this.service.agent, this.id, cb);
        this.id = this.app.getServerId();
        if (this.app.getServerType() === 'master') {
            if (this.service.master) {
                this.app.event.on(events.ADD_SERVERS, this._addEvent);
                this.app.event.on(events.REMOVE_SERVERS, this._removeEvent);
                this._masterWatcherModule = this.service.modules[KEYWORDS.MASTER_WATCHER].module;
            }
        } else {
            this.app.event.on(events.START_SERVER, this.afterStart.bind(this));
        }
        cb();
    }


    monitorHandler(agent: MonitorAgent, msg: any, cb: MonitorCallback) {
        if (!msg || !msg.action) {
            return;
        }
        switch (msg.action) {
            case 'afterStartCallback': {
                logger.warn('RestartNotifyModule afterStart notify ', this.id, msg);
                if (this.afterStartCalled) {
                    cb(1 as any);
                    break;
                }
                this.afterStartCallBack = cb;
                break;
            }
            default: {
                logger.error('RestartNotifyModule unknown action: %j', msg.action);
                return;
            }
        }
    }
}
