"use strict";

/**
 * Scheduler component to schedule message sending.
 */
/**
 * @access private
 */
const DefaultScheduler = require('../pushSchedulers/direct');
const logger = require('@sex-pomelo/sex-pomelo-logger').getLogger('pomelo', __filename);

module.exports = function(app, opts) {
  return new ComponentPushScheduler(app, opts);
};

/**
 * 
 * @class
 * @implements {Component}
 * 
 * @param {Object} app  current application context
 * @param {Object} opts construct parameters
 */
let ComponentPushScheduler = function(app, opts) {
  this.app = app;
  opts = opts || {};
  this.scheduler = getScheduler(this, app, opts);
};

ComponentPushScheduler.prototype.name = '__pushScheduler__';

/**
 * Component lifecycle callback
 *
 * @param {Function} cb
 * @return {Void}
 */
ComponentPushScheduler.prototype.afterStart = function(cb) {
  if(this.isSelectable) {
    for (let k in this.scheduler) {
      let sch = this.scheduler[k];
      if(typeof sch.start === 'function') {
        sch.start();
      }
    }
    process.nextTick(cb);
  } else if(typeof this.scheduler.start === 'function') {
    this.scheduler.start(cb);
  } else {
    process.nextTick(cb);
  }
};

/**
 * Component lifecycle callback
 *
 * @param {Function} cb
 * @return {Void}
 */
ComponentPushScheduler.prototype.stop = function(force, cb) {
  if(this.isSelectable) {
    for (let k in this.scheduler) {
      let sch = this.scheduler[k];
      if(typeof sch.stop === 'function') {
        sch.stop();
      }
    }
    process.nextTick(cb);
  } else if(typeof this.scheduler.stop === 'function') {
    this.scheduler.stop(cb);
  } else {
    process.nextTick(cb);
  }
};

/**
 * Schedule how the message to send.
 *
 * @param  {Number}   reqId request id
 * @param  {String}   route route string of the message
 * @param  {Object}   msg   message content after encoded
 * @param  {Array}    recvs array of receiver's session id
 * @param  {Object}   opts  options
 * @param  {Function} cb
 */

ComponentPushScheduler.prototype.schedule = function(reqId, route, msg, recvs, opts, cb) {
  let self = this;
  if(self.isSelectable) {
    if(typeof self.selector === 'function') {
      self.selector(reqId, route, msg, recvs, opts, function(id) {
        if(self.scheduler[id] && typeof self.scheduler[id].schedule === 'function') {
          self.scheduler[id].schedule(reqId, route, msg, recvs, opts, cb);
        } else {
          logger.error('invalid pushScheduler id, id: %j', id);
        }
      });
    } else {
      logger.error('the selector for pushScheduler is not a function, selector: %j', self.selector);
    }
  } else {
    if (typeof self.scheduler.schedule === 'function') {
      self.scheduler.schedule(reqId, route, msg, recvs, opts, cb);
    } else {
      logger.error('the scheduler does not have a schedule function, scheduler: %j', self.scheduler);
    }
  }
};

let getScheduler = function(pushSchedulerComp, app, opts) {
  let scheduler = opts.scheduler || DefaultScheduler;
  if(typeof scheduler === 'function') {
    return scheduler(app, opts);
  }

  if(Array.isArray(scheduler)) {
    let res = {};
    scheduler.forEach(function(sch) {
      if(typeof sch.scheduler === 'function') {
        res[sch.id] = sch.scheduler(app, sch.options);
      } else {
        res[sch.id] = sch.scheduler;
      }
    });
    pushSchedulerComp.isSelectable = true;
    pushSchedulerComp.selector = opts.selector;
    return res; 
  }

  return scheduler;
};