package notification

import (
	"strconv"

	"github.com/astaxie/beego/orm"

	"git.kingpenguin.tk/chteufleur/datahouse.git/xmpp"

	"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
	"git.kingpenguin.tk/chteufleur/datahouse.git/models/user"
	"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
)

const (
	UPPER           = ">"
	UPPER_OR_EQUALS = ">="
	LOWER           = "<"
	LOWER_OR_EQUALS = "<="
	EQUALS          = "=="
	NOT_EQUALS      = "!="
)

type NotificationCondition struct {
	Id        int64
	UserId    int64
	Condition string
	Value     int64
}

func init() {
	orm.RegisterModel(new(NotificationCondition))
}

func AddNotificationCondition(userId int64, condition string, value int64) (int64, error) {
	o := orm.NewOrm()
	o.Using(database.Alias)
	return o.Insert(&NotificationCondition{UserId: userId, Condition: condition, Value: value})
}

func UpdateNotificationCondition(id, userId int64, condition string, value int64) error {
	o := orm.NewOrm()
	o.Using(database.Alias)

	n := GetNotificationCondition(id)
	if o.Read(n) == nil {
		n.UserId = userId
		n.Condition = condition
		n.Value = value
		_, err := o.Update(n)
		return err
	}
	return nil
}

func DeleteNotificationCondition(id int64) {
	o := orm.NewOrm()
	o.Using(database.Alias)
	o.Delete(&NotificationCondition{Id: id})
}

func GetAllNotificationConditionIds() []int64 {
	o := orm.NewOrm()
	o.Using(database.Alias)

	notif := new(NotificationCondition)
	var ret []int64
	var maps []orm.Params
	_, err := o.QueryTable(notif).Values(&maps)
	if err == nil {
		for _, m := range maps {
			ret = append(ret, utils.GetInt(m, "Id"))
		}
	}
	return ret
}

func GetAllNotificationCondition() []NotificationCondition {
	o := orm.NewOrm()
	o.Using(database.Alias)

	notif := new(NotificationCondition)
	var maps []orm.Params
	var ret []NotificationCondition
	_, err := o.QueryTable(notif).Values(&maps)
	if err == nil {
		for _, m := range maps {
			n := new(NotificationCondition)
			n.Id = utils.GetInt(m, "Id")
			n.UserId = utils.GetInt(m, "UserId")
			n.Condition = utils.GetString(m, "Condition")
			n.Value = utils.GetInt(m, "Value")
			ret = append(ret, *n)
		}
	}

	return ret
}

func GetNotificationConditionByUser(idUser int64) []NotificationCondition {
	o := orm.NewOrm()
	o.Using(database.Alias)

	var ret []NotificationCondition
	var maps []orm.Params
	_, err := o.QueryTable(new(NotificationCondition)).Filter("UserId", idUser).Values(&maps)
	if err == nil {
		for _, m := range maps {
			n := new(NotificationCondition)
			n.Id = utils.GetInt(m, "Id")
			n.UserId = utils.GetInt(m, "UserId")
			n.Condition = utils.GetString(m, "Condition")
			n.Value = utils.GetInt(m, "Value")
			ret = append(ret, *n)
		}
	}

	return ret
}

func GetNotificationCondition(id int64) *NotificationCondition {
	o := orm.NewOrm()
	o.Using(database.Alias)

	var ret = new(NotificationCondition)
	var maps []orm.Params
	_, err := o.QueryTable(new(NotificationCondition)).Filter("Id", id).Values(&maps)
	if err == nil {
		for _, m := range maps {
			ret.Id = utils.GetInt(m, "Id")
			ret.UserId = utils.GetInt(m, "UserId")
			ret.Condition = utils.GetString(m, "Condition")
			ret.Value = utils.GetInt(m, "Value")
		}
	}

	return ret
}

func (n *NotificationCondition) IsConditionValidate(val int64) bool {
	ret := false

	if n.Condition == UPPER {
		ret = (val > n.Value)
	} else if n.Condition == UPPER_OR_EQUALS {
		ret = (val >= n.Value)
	} else if n.Condition == LOWER {
		ret = (val < n.Value)
	} else if n.Condition == LOWER_OR_EQUALS {
		ret = (val <= n.Value)
	} else if n.Condition == EQUALS {
		ret = (val == n.Value)
	} else if n.Condition == NOT_EQUALS {
		ret = (val != n.Value)
	}

	return ret
}

func (n *NotificationCondition) Notify(val int64, message string) {
	if n.IsConditionValidate(val) {
		u := user.GetUser(n.UserId)
		if u != nil && u.JID != "" {
			xmpp_manager.SendMessage(u.JID, "", "["+n.Condition+" "+strconv.FormatInt(n.Value, 10)+"] "+message)
		}
	}
}
