const System = require("../system");
const redis = require("redis");
const settings = require("../../config/settings");
const bluebird = require("bluebird");
bluebird.promisifyAll(redis);

// const logCtl=System.getObject("web.oplogCtl");
class RedisClient {
  constructor() {
    const redisConfig = settings.redis();
    this.client = redis.createClient({
      host: redisConfig.host,
      port: redisConfig.port,
      password: redisConfig.password,
      db: redisConfig.db,
      retry_strategy: function (options) {
        // if (options.error && options.error.code === 'ECONNREFUSED') {
        //     // End reconnecting on a specific error and flush all commands with
        //     // a individual error
        //     return new Error('The server refused the connection');
        // }
        if (options.total_retry_time > 1000 * 60 * 60) {
          // End reconnecting after a specific timeout and flush all commands
          // with a individual error
          return new Error('Retry time exhausted');
        }
        if (options.attempt > 10) {
          // End reconnecting with built in error
          return 10000;
        }
        // reconnect after
        return Math.min(options.attempt * 100, 3000);
      }
    });

    // return client.multi().get('foo').execAsync().then(function(res) {
    //     console.log(res); // => 'bar'
    // });
    this.client.on("error", function (err) {
      console.log("Error " + err);
      // //日志记录
      // logCtl.error({
      //    optitle:"redis this.client.on异常：",
      //    op:"base/utils/redisClient/this.client.on",
      //    content:err,
      //    clientIp:""
      //  });
    });
    this.subclient = this.client.duplicate();
    this.subclient.on("error", function (err) {
      console.log("Error " + err);
      // //日志记录
      // logCtl.error({
      //    optitle:"redis this.subclient.on异常：",
      //    op:"base/utils/redisClient/this.subclient.on",
      //    content:err,
      //    clientIp:""
      //  });
    });
    var self = this;
    this.subclient.on("message", async function (channel, message) {
      console.log(channel, '------------- redis message ------------------- ');

      if (self.taskmanager) {
        if (channel == "task") {
          if (message == "newtask") {
            (async (that) => {
              var msg2 = await that.rpop("tasklist");
              if (msg2) {
                console.log("taskName+++++" + msg2);
                var msgs2 = msg2.split("_");
                var action = msgs2[0];
                var taskName = msgs2[1];
                var exp = msgs2[2];
                await that.taskmanager.addTask(taskName, exp);
              }
            })(self)

          } else {
            (async (msg, that) => {
              var msgs = msg.split("_");
              var action = msgs[0];
              if (action == "delete") {
                var taskName = msgs[1];
                await that.taskmanager.deleteTask(taskName);
              }
            })(message, self);
          }
        }
      }
      if (self.chatserver) {
        if (channel != "task") {
          if (channel == "brc") {//如果是广播频道，则发送广播到客户端
            self.chatserver.server.emit("brc", JSON.parse(message));
          } else if (self.chatserver.users[channel]) {
            //持久化
            self.chatserver.users[channel].client.emit("chatmsg", JSON.parse(message));
          }
        }
      }
    });
  }

  async subscribe(channel, chatserver) {
    if (!this.chatserver) {
      this.chatserver = chatserver;
    }
    return this.subclient.subscribeAsync(channel);
  }

  async unsubscribe(channel) {
    //this.chatserver=null;
    return this.subclient.unsubscribeAsync(channel);
  }

  async subscribeTask(channel, taskmanager) {
    if (!this.taskmanager) {
      this.taskmanager = taskmanager;
    }
    return this.subclient.subscribeAsync(channel);
  }

  async publish(channel, msg) {
    console.log(channel + ":" + msg);
    return this.client.publishAsync(channel, msg);
  }

  async rpush(key, val) {
    return this.client.rpushAsync(key, val);
  }

  async llen(key) {
    return this.client.llenAsync(key);
  }

  async rpushWithEx(key, val, t) {
    var p = this.rpush(key, val);
    this.client.expire(key, t);
    return p;
  }

  async rpop(key) {
    return this.client.rpopAsync(key);
  }

  async lpop(key) {
    return this.client.lpopAsync(key);
  }

  async lrem(key, val) {
    return this.client.lremAsync(key, 1, val);
  }

  async ltrim(key, s, e) {
    return this.client.ltrimAsync(key, s, e);
  }

  async clearlist(key) {
    await this.client.ltrim(key, -1, -1);
    await this.client.ltrim(key, 1, -1);
    return 0;
  }

  async flushall() {
    console.log("sss");
    return this.client.flushallAsync();
  }

  async keys(p) {
    return this.client.keysAsync(p);
  }

  async set(key, val) {
    if (typeof val == "undefined" || typeof key == "undefined") {
      console.log("......................cache val undefined");
      console.log(key);
      return null;
    }
    return this.client.setAsync(key, val);
  }

  async setWithEx(key, val, t) {
    var p = this.client.setAsync(key, val);
    this.client.expire(key, t);
    return p;
  }

  async get(key) {

    return this.client.getAsync(key);
  }

  async delete(key) {
    return this.client.delAsync(key);
  }

  async hmset(key, jsonObj) {
    return this.client.hmsetAsync(key, jsonObj);
  }

  async hmsetWithEx(key, jsonObj, t) {
    var p = this.client.hmsetAsync(key, jsonObj);
    this.client.expire(key, t);
    return p;
  }

  async hgetall(key) {
    return this.client.hgetallAsync(key);
  }

  async hincrby(key, f, n) {
    return this.client.hincrbyAsync(key, f, n);
  }

  async sadd(key, vals) {
    await this.client.saddAsync(key, ...vals);
    return this.scard(key);
  }

  async scard(key) {
    return this.client.scardAsync(key);
  }

  async srem(key, val) {
    return this.client.sremAsync(key, val);
  }

  async sismember(key, val) {
    return this.client.sismemberAsync(key, val);
  }

  async smembers(key) {
    return this.client.smembersAsync(key);
  }

  async exists(key) {
    return this.client.existsAsync(key);
  }

  async incr(key) {
    return this.client.incrAsync(key);
  }

  async blpop(key, d) {
    return await this.client.blpopAsync(key, d);
  }

  async rpushBCD(v) {
    this.rpush("bpo:contract:download", JSON.stringify(v));
  }

  async genrateId(tableName) {
    // "时间戳 - tableName的hashCode  + （1000 - 9999） + 随机8位数"
    let time = parseInt(new Date().getTime() / 1000);
    let tabcode = this.hashCode(tableName);

    let id = await this.client.incrAsync(tableName) % 9999;
    if(id < 10) {
      id = "000" + id;
    } else if(id < 100) {
      id = "00" + id;
    } else if(id < 1000) {
      id = "0" + id;
    }
    return "1" + Math.abs(time + tabcode) + id + this.getRandomNumber(2);
  }

  hashCode(str) {
    let hash = 0;
    if (str.length == 0) return hash;
    for (var i = 0; i < str.length; i++) {
      let char = str.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash;
    }
    return hash;
  }

  getRandomNumber(len) {
    len = len || 32;
    let chars = '0123456789';
    let maxPos = chars.length;
    let pwd = '';
    for (var i = 0; i < len; i++) {
      pwd += chars.charAt(Math.floor(Math.random() * maxPos));
    }
    return pwd;
  }

}

module.exports = RedisClient;
// var client=new RedisClient();
// (async ()=>{
//   await client.rpush("tasklist","xxx");
//   await client.rpush("tasklist","xxx");
//   var len=await client.llen("tasklist");
//   //await client.clearlist("tasklist");
//   len=await client.llen("tasklist");
//   console.log(len);
// })()

// client.keys('*').then(s=>{
//   console.log(s);
// });
// let clients = {};
// clients.watcher = redis.createClient({ ... } );
// clients.alterer = clients.watcher.duplicate();
// client.sadd("h",["ok","jy","ok"]).then(function(r){
//   console.log(r);
// });
// client.smembers("h").then(function(r){
//   console.log(r);
// });
// client.sismember("h","ok").then(function(r){
//   console.log(r);
// });
// console.dir(client);ti.exec( callback )回调函数参数err：返回null或者Array，出错则返回对应命令序列链中发生错误的错误信息，这个数组中最后一个元素是源自exec本身的一个EXECABORT类型的错误
// r.set("hello","oooo").then(function(result){
//   console.log(result);
// });
// r.get("hello").then(function(result){
//   console.log(result);
// });
// client.hmset("user_1",{name:"jy",age:13}).then(function(r){
//   console.log(r);
//
// });
// client.hincrby("user_1","age",2).then(function(r){
//   console.log(r);
//   setTimeout(function(){
//     client.hgetall("user_1").then(function(u){
//       console.log(u);
//     });
//   },3000);
// });
