package svc

import (
	"errors"
	"net/rpc"

	"github.com/globalsign/mgo"
	"github.com/globalsign/mgo/bson"
	"mongo.games.com/game/dbproxy/mongo"
	"mongo.games.com/game/model"
	"mongo.games.com/goserver/core/logger"
)

func MessageCollection(plt string) *mongo.Collection {
	s := mongo.MgoSessionMgrSington.GetPltMgoSession(plt, model.MessageDBName)
	if s != nil {
		c, first := s.DB().C(model.MessageCollName)
		if first {
			c.EnsureIndex(mgo.Index{Key: []string{"snid"}, Background: true, Sparse: true})
			c.EnsureIndex(mgo.Index{Key: []string{"state"}, Background: true, Sparse: true})
		}
		return c
	}
	return nil
}

type MessageSvc struct {
}

var _MessageSvc = &MessageSvc{}

func init() {
	rpc.Register(_MessageSvc)
}

func (svc *MessageSvc) GetMessage(args *model.GetMessageArgs, ret *[]model.Message) error {
	logger.Logger.Info("MessageSvc GetMessage")
	c := MessageCollection(args.Plt)
	if c != nil {
		var sql []bson.M
		sql = append(sql, bson.M{"state": 0})
		sql = append(sql, bson.M{"state": 1})
		err := c.Find(bson.M{"snid": args.SnId, "$or": sql}).All(ret)
		return err
	}
	return nil
}

func (svc *MessageSvc) GetNotDelMessage(args *model.GetMessageArgs, ret *[]model.Message) error {
	logger.Logger.Info("MessageSvc GetMessage")
	c := MessageCollection(args.Plt)
	if c != nil {
		err := c.Find(bson.M{"snid": args.SnId, "state": bson.M{"$ne": model.MSGSTATE_REMOVEED}}).All(ret)
		return err
	}
	return nil
}

func (svc *MessageSvc) GetSubscribeMessage(args string, ret *[]model.Message) error {
	logger.Logger.Info("MessageSvc GetSubscribeMessage")
	c := MessageCollection(args)
	if c != nil {
		err := c.Find(bson.M{"snid": 0}).All(ret)
		return err
	}
	return nil
}
func (svc *MessageSvc) GetMessageInRangeTsLimitByRange(args *model.MsgArgs, ret *model.RetMsg) error {
	logger.Logger.Info("MessageSvc GetMessageInRangeTsLimitByRange")
	c := MessageCollection(args.Platform)
	if c == nil {
		return errors.New("c == nil")
	}
	limitDataNum := args.ToIndex - args.FromIndex
	if limitDataNum < 0 {
		limitDataNum = 0
	}
	var selecter bson.M
	if args.StartTs == 0 && args.EndTs == 0 {
		if len(args.Platform) == 0 {
			selecter = bson.M{"mtype": args.MsgType}
		} else {
			selecter = bson.M{"mtype": args.MsgType, "platform": args.Platform}
		}
	} else {
		if len(args.Platform) == 0 {
			selecter = bson.M{"mtype": args.MsgType, "creatts": bson.M{"$gte": args.StartTs, "$lte": args.EndTs}}
		} else {
			selecter = bson.M{"mtype": args.MsgType, "platform": args.Platform, "creatts": bson.M{"$gte": args.StartTs, "$lte": args.EndTs}}
		}
	}
	if args.DestSnId != -1 {
		selecter["snid"] = args.DestSnId
	}
	//下面的Count和Skip均是Mgo中比较耗时的操作，根据线上日志来看两个语句执行时间已经超过10s(具体mgo中数据量保密)
	//那重点就根据业务优化下面两句即可
	count, _ := c.Find(selecter).Count()
	err := c.Find(selecter).Skip(args.FromIndex).Limit(limitDataNum).All(&ret.Msg)
	ret.Count = count
	return err
}

func (svc *MessageSvc) ReadMessage(args *model.ReadMsgArgs, ret *bool) error {
	logger.Logger.Info("MessageSvc ReadMessage")
	c := MessageCollection(args.Platform)
	if c != nil {
		err := c.Update(bson.M{"_id": args.Id}, bson.D{{"$set", bson.D{{"state", model.MSGSTATE_READED}}}})
		if err != nil {
			return err
		}
		*ret = true
	}
	return nil
}
func (svc *MessageSvc) DelMessage(args *model.DelMsgArgs, ret *bool) error {
	logger.Logger.Info("MessageSvc DelMessage")
	c := MessageCollection(args.Platform)
	if c != nil {
		var err error
		if args.Del == 0 {
			err = c.Remove(bson.M{"_id": args.Id}) // 目前需求
		} else {
			err = c.Update(bson.M{"_id": args.Id}, bson.D{{"$set", bson.D{{"state", model.MSGSTATE_REMOVEED}}}})
		}
		if err != nil {
			return err
		}
		*ret = true
	}
	return nil
}
func (svc *MessageSvc) DelAllMessage(args *model.DelAllMsgArgs, ret *bool) error {
	logger.Logger.Info("MessageSvc DelMessage")
	c := MessageCollection(args.Platform)
	if c != nil {
		//for _, id := range args.Ids {
		//	var err error
		//	if args.Del == 0 {
		//		err = c.Remove(bson.M{"_id": id}) // 目前需求
		//	} else {
		//		err = c.Update(bson.M{"_id": id}, bson.D{{"$set", bson.D{{"state", model.MSGSTATE_REMOVEED}}}})
		//	}
		//	if err != nil {
		//		return err
		//	}
		//}
		//*ret = true
		_, err := c.RemoveAll(bson.M{"oper": 1, "state": model.MSGSTATE_REMOVEED})
		err = c.Remove(bson.M{"oper": 1, "state": model.MSGSTATE_REMOVEED})
		if err != nil && err != mgo.ErrNotFound {
			logger.Logger.Error("DelAllMessage:", err)
			return err
		}
		*ret = true
	}
	return nil
}
func (svc *MessageSvc) GetMessageAttach(args *model.AttachMsgArgs, ret *bool) error {
	logger.Logger.Info("MessageSvc GetMessageAttach")
	c := MessageCollection(args.Platform)
	if c != nil {
		err := c.Update(bson.M{"_id": args.Id}, bson.D{{"$set", bson.D{{"attachstate", model.MSGATTACHSTATE_GOT}}}})
		if err != nil {
			return err
		}
		*ret = true
	}
	return nil
}
func (svc *MessageSvc) GetMessageById(args *model.GetMsgArg, ret *model.Message) error {
	logger.Logger.Info("MessageSvc GetMessageById")
	c := MessageCollection(args.Platform)
	if c != nil {
		Id := bson.ObjectIdHex(args.IdStr)
		err := c.Find(bson.M{"_id": Id}).One(ret)
		return err
	}
	return nil
}

func (svc *MessageSvc) GetMessageAttachs(args *model.AttachMsgsArgs, ret *[]string) error {
	logger.Logger.Info("MessageSvc GetMessageAttachs")
	c := MessageCollection(args.Platform)
	if c != nil {
		for _, Idstr := range args.Ids {
			Id := bson.ObjectIdHex(Idstr)
			var msg model.Message
			if err := c.Find(bson.M{"_id": Id}).One(&msg); err == nil {
				if msg.AttachState == model.MSGATTACHSTATE_GOT {
					continue
				}
				err := c.Update(bson.M{"_id": Id}, bson.D{{"$set", bson.D{{"attachstate", model.MSGATTACHSTATE_GOT}}}})
				if err != nil {
					logger.Logger.Infof("MessageSvc GetMessageAttachs attachstate err %v", err)
					continue
				}

				*ret = append(*ret, msg.Id.Hex())
			}

		}
		return nil
	}
	return errors.New("redis is nil")
}

func (svc *MessageSvc) InsertMessage(args *model.InsertMsgArg, ret *bool) error {
	//logger.Logger.Trace("MessageSvc InsertMessage")
	c := MessageCollection(args.Platform)
	var err error
	if c != nil {
		if len(args.Msgs) == 1 {
			err = c.Insert(args.Msgs[0])
		} else if len(args.Msgs) > 1 {
			docs := make([]interface{}, 0, len(args.Msgs))
			for _, msg := range args.Msgs {
				docs = append(docs, msg)
			}
			err = c.Insert(docs...)
		}
		if err != nil {
			return err
		}
		*ret = true
	}
	return nil
}
func (svc *MessageSvc) RemoveMessages(args *model.AttachMsgArgs, ret *mgo.ChangeInfo) (err error) {
	logger.Logger.Info("MessageSvc GetMessageAttach")
	c := MessageCollection(args.Platform)
	if c != nil {
		ret, err = c.RemoveAll(bson.M{"creatts": bson.M{"$lt": args.Ts}})
	}
	return
}
