package main

import (
	"../gameapi"
	"../log"
	"../mod"
	"../nnet"
	"../nt"
	pb "../protos"
	"../utils"
	"fmt"
	"github.com/coheneye/go-simplejson"
	"github.com/gogo/protobuf/proto"
	"go.uber.org/zap"
	"strconv"
	"time"
)

func do_C_QueryMessage(ses nnet.ISession, req *pb.Request) {
	PostUserNewMessages(req.Guid)
}

func do_C_Config(ses nnet.ISession, req *pb.Request) {
	SendToClient(ses, req.Guid, nt.DynConf.ClientAddrsConf)
}

func do_C_Notice(ses nnet.ISession, req *pb.Request) {
	p := &pb.C_Notice{}
	r := &pb.S_Notice{}

	defer func() {
		SendToClient(ses, req.Guid, r)
	}()

	err := proto.Unmarshal(req.Req, p)
	if nil != err {
		r.Ec = int32(pb.ErrCode_BAD_REQUEST)
		return
	}

	// TODO: 优化到 zookeeper
	// 获取所有通知
	m, err := mod.GetNotices()
	if err != nil {
		r.Ec = int32(pb.ErrCode_FAILED)
		return
	}
	now := time.Now().Unix()
	for sid, notice := range m {
		js, err := simplejson.NewJson([]byte(notice))
		if nil != err {
			log.Info("bad notice", zap.String("notice", sid))
			continue
		}
		//TODO: 只要param
		params := js.Get("params")

		id := params.Get("id").MustInt64()
		end_time := params.Get("end_time").MustInt64()
		if end_time < now {
			err = mod.RemoveNotices(id)
			if nil != err {
				log.Warn("remove notice", zap.Int64("id", id))
			}
			continue
		}

		r.Notices = append(r.Notices, &pb.Notice{
			Id:      int32(id),
			Title:   params.Get("title").MustString(),
			Content: params.Get("content").MustString(),
			Time:    params.Get("start_time").MustInt64(),
			Endat: 	 end_time,
		})
	}
}

func do_C_Activity(ses nnet.ISession, req *pb.Request) {
	p := &pb.C_Activity{}
	r := &pb.S_Activity{}

	err := proto.Unmarshal(req.Req, p)
	if nil != err {
		r.Ec = int32(pb.ErrCode_BAD_REQUEST)
		SendToClient(ses, req.Guid, r)
		return
	}

	jsn, err := mod.GetActivities()
	if nil != err {
		r.Ec = int32(pb.ErrCode_FAILED)
		SendToClient(ses, req.Guid, r)
		return
	}

	r.Jsn = jsn

	SendToClient(ses, req.Guid, r)
}

func do_C_VIPInfo(ses nnet.ISession, req *pb.Request) {
	p := &pb.C_VIPInfo{}
	r := &pb.S_VIPInfo{}

	defer func() {
		SendToClient(ses, req.Guid, r)
	}()

	err := proto.Unmarshal(req.Req, p)
	if nil != err {
		r.Ec = int32(pb.ErrCode_BAD_REQUEST)
		return
	}
	// get current
	arr, err := mod.GetUserAttrs(req.Guid, "vip", "bets")
	if err != nil {
		r.Ec = int32(pb.ErrCode_UNKNOWN)
		log.Error("GetUserAttrs", zap.Uint64("guid", req.Guid), zap.Error(err))
		return
	}
	level := utils.If_to_int32(arr[0], 1)
	bets := utils.If_to_int64(arr[1], 0)

	lvl, v, err := nt.GetVIPByBets(bets)
	if nil != err {
		r.Ec = int32(pb.ErrCode_UNKNOWN)
		log.Error("GetVIPByBets", zap.Error(err), zap.Uint64("guid", req.Guid), zap.Int64("bets", bets))
		return
	}
	// 升级就更新
	if lvl > level {
		go func() {
			err = mod.UpdateUserAttr(req.Guid, "vip", lvl)
			if nil != err {
				log.Warn("UpdateUserAttr", zap.Error(err), zap.Uint64("guid", req.Guid), zap.Int32("lvl", lvl))
			}
		}()
	}
	unow := time.Now().Unix()
	r.Level = lvl
	r.Bets = bets
	r.Target = GetNextVipNeed(lvl)
	r.Bonus = append(r.Bonus, &pb.ValueTimes{}, &pb.ValueTimes{}, &pb.ValueTimes{}, &pb.ValueTimes{})
	if v.Bonus > 0 {
		single, err := mod.VipGetBonus(req.Guid)
		if err != nil {
			r.Ec = int32(pb.ErrCode_UNKNOWN)
			log.Error("VipGetBonus", zap.Uint64("guid", req.Guid), zap.Error(err))
			return
		}
		if single < v.Bonus*100 {
			r.Bonus[0].Val = v.Bonus * 100
			r.Bonus[0].Times = 1
		}
	} else {
		log.Debug("bonus < 0", zap.Uint64("guid", req.Guid), zap.Int32("lvl", lvl))
	}
	if v.Weekly > 0 {
		last, err := mod.VipGetWeekly(req.Guid)
		if err != nil {
			r.Ec = int32(pb.ErrCode_UNKNOWN)
			log.Error("VipGetWeekly", zap.Uint64("guid", req.Guid))
			return
		}
		if LastMonday(unow) != LastMonday(last) {
			r.Bonus[1].Val = v.Weekly * 100
			r.Bonus[1].Times = 1
		}
	} else {
		log.Debug("weekly < 0", zap.Uint64("guid", req.Guid), zap.Int32("lvl", lvl))
	}
	if v.Monthly > 0 {
		last, err := mod.VipGetMonthly(req.Guid)
		if err != nil {
			log.Error("VipGetMonthly", zap.Uint64("guid", req.Guid))
			r.Ec = int32(pb.ErrCode_UNKNOWN)
			return
		}
		if Last1stMonthday(unow) != Last1stMonthday(last) {
			r.Bonus[2].Val = v.Monthly * 100
			r.Bonus[2].Times = 1
		}
	} else {
		log.Debug("monthly < 0", zap.Uint64("guid", req.Guid), zap.Int32("lvl", lvl))
	}

	if v.AlmsAmount > 0 {
		amount, times, _ := alms_status(req.Guid)
		r.Bonus[3].Val = amount
		r.Bonus[3].Times = int32(times)
	}else{
		log.Debug("alms <= 0", zap.Uint64("guid", req.Guid), zap.Int32("lvl", lvl))
	}

	r.Conf = nt.DynConf.Vip
}

func do_C_GetVipBonus(ses nnet.ISession, req *pb.Request) {
	p := &pb.C_GetVipBonus{}
	r := &pb.S_GetVipBonus{}

	err := proto.Unmarshal(req.Req, p)
	if nil != err {
		log.Error("do_C_GetVipBonus", zap.Error(err))
		r.Ec = int32(pb.ErrCode_BAD_REQUEST)
		SendToClient(ses, req.Guid, r)
		return
	}
	sl, err := mod.GetUserAttr(req.Guid, "vip")
	if err != nil {
		log.Error("do_C_GetVipBonus", zap.Error(err))
		r.Ec = int32(pb.ErrCode_UNKNOWN)
		SendToClient(ses, req.Guid, r)
		return
	}
	level, err := strconv.ParseInt(sl, 10, 32)
	if nil != err {
		log.Error("do_C_GetVipBonus", zap.Error(err))
		r.Ec = int32(pb.ErrCode_UNKNOWN)
		SendToClient(ses, req.Guid, r)
		return
	}

	var got int64 = 0
	var ec pb.ErrCode
	var newBalance int64
	var reason int32
	switch p.Type {
	case int32(pb.VipBonus_Single):
		newBalance, got, ec = UserGetSingle(req.Guid, int32(level))
		reason = int32(pb.ReasonBalanceChange_VIP)
	case int32(pb.VipBonus_Weekly):
		newBalance, got, ec = UserGetWeekly(req.Guid, int32(level))
		reason = int32(pb.ReasonBalanceChange_VIP_WEEKLY)
	case int32(pb.VipBonus_Monthly):
		newBalance, got, ec = UserGetMonthly(req.Guid, int32(level))
		reason = int32(pb.ReasonBalanceChange_VIP_MONTHLY)
	case int32(pb.VipBonus_Alms):
		newBalance, got, ec = alms_get(req.Guid)
		reason = int32(pb.ReasonBalanceChange_ALMS)
	default:
		newBalance, got, ec = 0, 0, pb.ErrCode_BAD_REQUEST
	}
	r.Ec = int32(ec)
	r.Type = p.Type
	r.Level = int32(level)
	r.Delta = got

	SendToClient(ses, req.Guid, r)
	if ec == pb.ErrCode_OK && got > 0 {
		Ev.OnUserReward(req.Guid, got, newBalance, reason, ses)
	}else{
		log.Error("do_C_GetVipBonus", zap.Uint64("guid", req.Guid), zap.Int32("ec", r.Ec),
			zap.Int64("got", got))
	}
}

func do_C_Checkin7(ses nnet.ISession, req *pb.Request) {
	p := &pb.C_Checkin7{}
	r := &pb.S_Checkin7{}

	err := proto.Unmarshal(req.Req, p)
	if nil != err {
		log.Error("do_C_Checkin7", zap.Error(err))
		r.Ec = int32(pb.ErrCode_BAD_REQUEST)
		SendToClient(ses, req.Guid, r)
		return
	}
	ec := Checkin7GetUserStatus(req.Guid, r)
	if ec != pb.ErrCode_OK {
		log.Error("do_C_Checkin7", zap.Uint64("guid", req.Guid), zap.Int32("ec", int32(ec)))
	}
	r.Ec = int32(ec)
	r.Conf = nt.DynConf.Checkin7

	SendToClient(ses, req.Guid, r)
}

func do_C_CheckinGet(ses nnet.ISession, req *pb.Request) {
	p := &pb.C_CheckinGet{}
	r := &pb.S_CheckinGet{}

	err := proto.Unmarshal(req.Req, p)
	if nil != err {
		log.Error("do_C_CheckinGet", zap.Error(err))
		r.Ec = int32(pb.ErrCode_BAD_REQUEST)
		SendToClient(ses, req.Guid, r)
		return
	}
	newBalance, delta, ec := Checkin7GetBonus(req.Guid, p.Day)
	if ec != pb.ErrCode_OK {
		log.Error("do_C_CheckinGet", zap.Uint64("guid", req.Guid), zap.Int32("ec", int32(ec)))
	}

	r.Ec = int32(ec)
	r.Delta = delta
	SendToClient(ses, req.Guid, r)

	if ec == pb.ErrCode_OK {
		Ev.OnUserReward(req.Guid, delta, newBalance, int32(pb.ReasonBalanceChange_CHECKIN), ses)
	}
}

func do_C_GetGameTask(ses nnet.ISession, req *pb.Request) {
	fmt.Printf("%v", req)
	r := &pb.S_GameTask{}

	var task gameapi.TaskHeader
	if gameapi.GetGameTaskByGuid(req.Guid, &task) {
		r.Ec = int32(pb.ErrCode_OK)
		for i := 0; i < len(task.Tasks); i++ {
			item := &pb.GameTask{}
			item.Reward = task.Tasks[i].Reward
			item.State = int32(task.Tasks[i].State)
			item.Name = task.Tasks[i].Name
			item.TaskId = int32(task.Tasks[i].TaskId)
			item.GameId = int32(task.Tasks[i].GameId)
			item.GameParam = task.Tasks[i].GameParam
			item.Target = int32(task.Tasks[i].Target)
			item.Finished = int32(task.Tasks[i].Finished)
			item.Limit = task.Tasks[i].Limit
			item.Received = int32(task.Tasks[i].Received)
			r.GameTasks = append(r.GameTasks, item)
		}
	} else {
		r.Ec = int32(pb.ErrCode_UNKNOWN)
	}

	SendToClient(ses, req.Guid, r)
}

func do_C_ReceiveTaskReward(ses nnet.ISession, req *pb.Request) {
	p := &pb.C_ReceiveReward{}
	r := &pb.S_ReceiveReward{}
	if err := proto.Unmarshal(req.Req, p); err != nil {
		r.Ec = int32(pb.ErrCode_BAD_REQUEST)
		SendToClient(ses, req.Guid, r)
		log.Debug("do_C_ReceiveTaskReward back data", zap.Any("GameTask", r))
		return
	}

	task := &pb.GameTask{}
	newBalnce, reward, isOk := gameapi.ReceiveReward(req.Guid, int(p.TaskId), task)
	if isOk {
		r.Ec = int32(pb.ErrCode_OK)
		r.GameTask = task
		Ev.OnUserReward(req.Guid, reward, newBalnce, int32(pb.ReasonBalanceChange_TASK), ses)
	} else {
		log.Warn("do_C_ReceiveTaskReward", zap.Uint64("guid", req.Guid), zap.Int32("taskId", p.TaskId))
		r.Ec = int32(pb.ErrCode_FAILED)
	}
	SendToClient(ses, req.Guid, r)
}

func do_C_Alms(ses nnet.ISession, req *pb.Request) {
	p := &pb.C_Alms{}
	r := &pb.S_Ntf_Alms{}

	err := proto.Unmarshal(req.Req, p)
	if nil != err {
		r.Ec = int32(pb.ErrCode_BAD_REQUEST)
		SendToClient(ses, req.Guid, r)
		return
	}

	amount, times, ec := alms_status(req.Guid)

	r.Ec = int32(ec)
	r.Times = int32(times)
	r.Amount = amount

	SendToClient(ses, req.Guid, r)
}

func do_C_AlmsGet(ses nnet.ISession, req *pb.Request) {
	p := &pb.C_AlmsGet{}
	r := &pb.S_AlmsGet{}

	err := proto.Unmarshal(req.Req, p)
	if nil != err {
		log.Error("do_C_AlmsGet", zap.Uint64("guid", req.Guid), zap.Error(err))
		r.Ec = int32(pb.ErrCode_BAD_REQUEST)
		SendToClient(ses, req.Guid, r)
		return
	}

	newBalance, delta, ec := alms_get(req.Guid)
	r.Ec = int32(ec)
	r.Amount = delta
	SendToClient(ses, req.Guid, r)

	if ec == pb.ErrCode_OK {
		Ev.OnUserReward(req.Guid, delta, newBalance, int32(pb.ReasonBalanceChange_ALMS), ses)
	}
}

func do_C_Unread(ses nnet.ISession, req *pb.Request) {
	p := &pb.C_Unread{}

	err := proto.Unmarshal(req.Req, p)
	if nil != err {
		log.Error("do_C_Unread", zap.Uint64("guid", req.Guid), zap.Error(err))
		return
	}

	PostUserUnreadCS(ses, req.Guid)
}

func do_C_Marquee(ses nnet.ISession, req *pb.Request) {
	p := &pb.C_Unread{}

	err := proto.Unmarshal(req.Req, p)
	if nil != err {
		log.Error("do_C_Unread", zap.Uint64("guid", req.Guid), zap.Error(err))
		return
	}

	PostUserMarquee(ses)
}