var Server = require('socket.io');
var system = require('../base/system');
var redisClient = system.getObject("util.redisClient");
const redisAdapter = require('socket.io-redis');
const uuidv4 = require('uuid/v4');
const msghistoryCtl = system.getObject("web.msg.msghistoryCtl");
const msgnoticeCtl = system.getObject("web.msg.msgnoticeCtl");
// const msgHistoryService = system.getObject("service.msghistorySve");
class RoomSet {
  constructor(server) {
    this.server = server
    this.roomsetkey = "roomset";//房间集
    this.membersetkey = "memberset";//人员集
    this.ownroomsurfix = "_own"
    this.onlinekey = "_onlines"
    this.init();
  }
  init () {

  }
  /**
   * 按照房间名查看人员
   */
  async clientsByRoom (roomname) {
    let rlst = await redisClient.lrange(roomname)
    return rlst
  }
  /**
   * 查看所有当前在线人数
   */
  async allmembers () {
    let ms = await redisClient.smembers(this.membersetkey);
    return ms
  }
  /**
   * 查看所有房间
   */
  async allrooms () {
    let rms = await redisClient.smembers(this.roomsetkey);
    return rms
  }

  /**
   *  查看某人拥有的房间
   *  已经排除私人房间
   * @param {*} ukstr 
   */
  async ownRooms (ukstr) {
    let rms = await redisClient.smembers(ukstr + this.ownroomsurfix);
    return rms
  }

  /**
   * 房间登记
   * @param {*} roomname 
   */
  async joinRoom (roomname, ukencstr) {
    //缓存所有房间名称
    await redisClient.sadd(this.roomsetkey, [roomname])
    //房间中缓存链接的客户uk,第一个人就是房主
    //检查是否已经存在todo
    await redisClient.rpush(roomname, ukencstr)
    //缓存某人拥有的房间,排除私人房间,为了显示群聊
    if (roomname != ukencstr) {
      await redisClient.sadd(ukencstr + this.ownroomsurfix, [roomname])
    }
    // 订阅房间消息,进入一个房间就要订阅这个房间的消息
    await redisClient.subscribe(roomname, this.server);

    //发送新登录用户的广播
    if (roomname == ukencstr) {
      let onlineperson = this.server.buildOnlineValue(ukencstr)
      let countonlines = await redisClient.sadd(this.onlinekey, [onlineperson])
      console.log("current lines....", countonlines)
      redisClient.publish("brc", "new user  login....online count:" + countonlines)
    }
    return {}
  }

  async reJoinRooms (ukstr) {
    let ownedRooms = await this.ownRooms(ukstr)
    console.log(ownedRooms)
    for (let r of ownedRooms) {
      redisClient.subscribe(r)
    }
  }

  /**
   * 解决当断开链接时，清除在断开节点上的原有房间订阅
   * @param {*} ukstr 
   */
  async unsubscribeOwnedRooms (ukstr) {
    let ownedRooms = await this.ownRooms(ukstr)
    for (let r of ownedRooms) {
      await redisClient.unsubscribe(r)
    }
  }

  /**
   * ukencstr 从房间 roomname退出
   * @param {*} roomname 
   * @param {*} ukencstr 
   */
  async exitRoom (roomname, ukencstr) {
    //清除某人拥有的房间缓存
    await redisClient.srem(ukencstr + this.ownroomsurfix, roomname)
    //从房间退出
    await redisClient.lrem(roomname, ukencstr)
    //是否房间里已经没人，如果没有了
    let personCountInRoom = await redisClient.llen(roomname)
    if (personCountInRoom == 0) {//如果房间没有人，就取消
      await redisClient.delete(roomname)
      //从房间缓存中删除
      await redisClient.srem(this.roomsetkey, roomname)
      //房间订阅取消
      await redisClient.unsubscribe(roomname)
    }
    return {}
  }
}
class MsgHandler {
  constructor(server, client) {
    this.server = server;
    this.client = client;
    this.init();
  }
  notifyClient (ukchannel, msg) {
    var msgH = { msgType: "system", sender: "s￥s￥s￥s", target: msg.to, content: msg.content };
    msgHistoryService.create(msgH).then((m) => {
      redisClient.publish(ukchannel, JSON.stringify(msg));
    }).catch(e => {
      console.log(e);
    });
  }
  init () {
    var self = this;
    //转发通信消息
    this.client.on("chatmsg", msg => {
      const from = msg.from;
      const to = msg.to;
      const msgContent = msg.content;
      //发布消息
      //持久化消息
      //取出当前人的头像,昵称
      //如果目标是房间频道
      //加入房间的时候,前端需要给出房间名称，需要指定房间默认的logo
      // let nickNameFrom = self.server.uinfos[from].nickName
      // let headUrlFrom = self.server.uinfos[from].headUrl
      // let nickNameTo = self.server.uinfos[to].nickName
      // let headUrlTo = self.server.uinfos[to].headUrl
      var msgH = {
        msgType: msg.type ? msg.type : "single",
        senderId: msg.from,
        sender: msg.nickNameForm,
        fromHeadUrl: msg.headUrlFrom,
        targetId: msg.to,
        target: msg.nickNameTo,
        toHeadUrl: msg.headUrlTo,
        content: msg.content
      };
      msgHistoryService.saveMsg(msgH).then((m) => {
        redisClient.publish(to, JSON.stringify(msg));
      }).catch(e => {
        console.log(e);
      });
      //self.server.users[to].emit("chatmsg",msg);
    });
    //http-proxy转发处理
    //响应消息处理
    this.client.on("replymsg", (msg, fn) => {
      var p = null;
      console.log("web." + msg.pkgname + "." + msg.cls, "mmmmmmmmmmmmmmmmmmmmmm")
      var invokeObj = system.getObject("web." + msg.pkgname + "." + msg.cls);
      console.log(invokeObj, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
      if (invokeObj[msg.method]) {
        p = invokeObj[msg.method].apply(invokeObj, [msg.data]);
      }
      p.then(r => {
        fn(r);
      }).then(() => {
        console.log("call success")
      }).catch(err => {
        console.log(err)
      })
    });
  }

}
class SocketServer {
  constructor(httpServer) {
    this.server = Server(httpServer, {
      serveClient: false,
      cookie: true
    });
    // this.server.adapter(redisAdapter({ pubClient: redisClient.client, subClient: redisClient.subclient }));
    this.server.engine.generateId = (req) => {
      // console.log(req.headers)
      return "custom:id:" + this.getUUID(); // custom id must be unique
    }
    this.users = {}//缓存所有客户端处理器
    this.uinfos = {}//缓存用户信息
    this.socketidMap = {}//缓存会话ID与房间KEY
    this.init()
  }
  getUUID () {
    var uuid = uuidv4();
    var u = uuid.replace(/\-/g, "");
    return u;
  }
  buildOnlineValue (ukencstr) {
    let onlineperson = `${this.uinfos[ukencstr].userName
      }|${this.uinfos[ukencstr].nickName}|${this.uinfos[ukencstr].headUrl}|${ukencstr}`
    return onlineperson
  }
  init () {
    var self = this;
    //挂载到web应用的控制器,开放消息服务器的rest接口调用
    msghistoryCtl.setSocketServer(self);
    msgnoticeCtl.setSocketServer(self);
    //初始化房间集合
    this.rooms = new RoomSet(self)
    //订阅广播频道
    redisClient.subscribe("brc", self);
    //中间件可以在链接事件发出前调用一次
    this.server.on('connection', function (client) {
      console.log("connection.....socket");
      client.on("login", (d, fn) => {
        //匿名用户,userName--访客前端给个uuid,id也取uuid,company-id是-1,表示匿名用户
        let uname = d.userName
        let nickName = d.nickName ? d.nickName : uname
        let headUrl = d.headUrl ? d.headUrl : 'https://gsb-zc.oss-cn-beijing.aliyuncs.com/zc_picUrl344116000745887092020814.jpg'
        let id = d.id
        let encuk = {
          companyid: d.company.id,
          userid: id,
          userName: uname,
          nickName: nickName,
          headUrl: headUrl
        }
        // let str = system.encriptByDes(JSON.stringify(encuk))
        //console.log('encstr', str)
        let uk = uname + "_" + id + "_" + d.company.id
        //作为房间key
        let ukencstr = system.encriptByDes(JSON.stringify(uk))
        encuk.uid = ukencstr
        if (self.socketidMap[client.id] && d.company.id != -1) {//可能匿名登录过
          let prevukstr = self.socketidMap[client.id]
          console.log("rm ano...", prevukstr)
          delete self.users[prevukstr]
          delete self.uinfos[prevukstr]
          self.rooms.exitRoom(prevukstr, prevukstr)
        }
        self.socketidMap[client.id] = ukencstr
        //保存所有的客户端的消息处理器
        self.users[ukencstr] = new MsgHandler(self, client)
        self.uinfos[ukencstr] = encuk

        //(订阅uk)开私人频道房间,并缓存房间名
        self.rooms.joinRoom(ukencstr, ukencstr)
        //初始化当前uk,历史未退出的房间,重新在新的节点订阅
        self.rooms.reJoinRooms(ukencstr)
        return fn(encuk)
      });
      //链接断开事件
      client.on('disconnect', async function (r) {
        console.log("connection.........................................dismiss.............", client.id, r);
        let ukencstr = self.socketidMap[client.id]
        console.log(ukencstr, "ddddddddddddd")
        if (ukencstr && ukencstr != "undefined") {
          console.log(ukencstr, "will delete.....")

          //删除在线人数
          let currentpersonstr = self.buildOnlineValue(ukencstr)
          await redisClient.srem(self.rooms.onlinekey, currentpersonstr)

          //断开链接时,从自己私人房间退出
          self.rooms.exitRoom(ukencstr, ukencstr)
          //取消当前人在当前节点，对其它房间的订阅,但不清除曾经加入过的房间，除非显式退出房间
          self.rooms.unsubscribeOwnedRooms(ukencstr)



          //当前在线人数
          let c = await redisClient.scard(self.rooms.onlinekey)
          self.server.emit("brc", "current user:" + c)

          //删除私人房间uk
          delete self.socketidMap[client.id]

          delete self.users[ukencstr]
          delete self.uinfos[ukencstr]

        }

      });
    });
  }

}
module.exports = SocketServer;
