package handler

import (
	"log"
	"regexp"
	"strings"

	"git.lxtend.com/lixiangwuxian/qqbot/auth"
	"git.lxtend.com/lixiangwuxian/qqbot/constants"
	"git.lxtend.com/lixiangwuxian/qqbot/model"
	"git.lxtend.com/lixiangwuxian/qqbot/util"
)

var allGroupHandlers = make(map[string]model.HandlerInfo[model.Handler])
var GroupHandlers = make(map[int64]map[string]model.HandlerInfo[model.Handler])
var frontMatchHandlers = make(map[string]model.HandlerInfo[model.Handler])
var regexHandlers = make(map[string]model.HandlerInfo[model.Handler])
var liveHandlers = make(map[int64]map[int64]model.TryCatchHandler)
var livePrivateHandlers = make(map[int64]model.TryCatchHandler)
var HelpInforms = make(map[string][]model.HelpInform)
var privateAllHandler model.Handler

func RegisterPrivateHandler(handler model.Handler) {
	privateAllHandler = handler
}

func RegisterHandler(trigger string, handler model.Handler, level constants.PermissionLevel) {
	allGroupHandlers[trigger] = model.HandlerInfo[model.Handler]{
		Trigger: trigger,
		Handler: handler,
		Level:   level,
	}
}

func RegisterFrontMatchHandler(trigger string, handler model.Handler, level constants.PermissionLevel) {
	frontMatchHandlers[trigger] = model.HandlerInfo[model.Handler]{
		Trigger: trigger,
		Handler: handler,
		Level:   level,
	}
}

func RegisterLiveHandler(groupID int64, userID int64, handler model.TryCatchHandler) { //userID=-1 means for all users in groupID
	if groupID == 0 {
		livePrivateHandlers[userID] = handler
		return
	}
	if _, ok := liveHandlers[groupID]; !ok {
		liveHandlers[groupID] = make(map[int64]model.TryCatchHandler)
	}
	liveHandlers[groupID][userID] = handler
}

func UnRegisterLiveHandler(groupID int64, userID int64) {
	if groupID == 0 {
		delete(livePrivateHandlers, userID)
		return
	}
	if _, ok := liveHandlers[groupID]; ok {
		delete(liveHandlers[groupID], userID)
	}
}

func RegisterGroupHandler(groupID int64, trigger string, handler model.Handler, level constants.PermissionLevel) {
	if _, ok := GroupHandlers[groupID]; !ok {
		GroupHandlers[groupID] = make(map[string]model.HandlerInfo[model.Handler])
	}
	GroupHandlers[groupID][trigger] = model.HandlerInfo[model.Handler]{
		Trigger: trigger,
		Handler: handler,
		Level:   level,
	}
}

func UnRegisterGroupHandler(groupID int64, trigger string) {
	if _, ok := GroupHandlers[groupID]; ok {
		delete(GroupHandlers[groupID], trigger)
	}
}

func RegisterRegexHandler(trigger string, handler model.Handler, level constants.PermissionLevel) {
	regexHandlers[trigger] = model.HandlerInfo[model.Handler]{
		Trigger: trigger,
		Handler: handler,
		Level:   level,
	}
}

func MsgInHandler(msg model.Message) (reply *model.Reply) {
	defer util.ReportPanicToDev()
	if msg.RawMsg != "" {
		log.Default().Printf("\033[31m↓\033[0m:%v", msg)
	} else {
		return nil
	}
	defer func() {
		if reply != nil {
			// log.Default().Printf("\033[32m↑\033[0m:%v", reply)
		}
	}()
	if handlerUserID, ok := liveHandlers[msg.GroupInfo.GroupId]; ok {
		if handler, ok := handlerUserID[msg.UserId]; ok {
			reply, catched := handler(msg)
			if catched {
				return reply
			}
		}
	}
	if handler, ok := livePrivateHandlers[msg.UserId]; ok {
		reply, catched := handler(msg)
		if catched {
			return reply
		}
	}
	for trigger, handler := range frontMatchHandlers {
		if strings.HasPrefix(msg.RawMsg, trigger) {
			return auth.TryExecHandler(msg, handler.Level, handler.Handler)
		}
	}
	msgArray := strings.Split(msg.RawMsg, " ")
	if handler, ok := allGroupHandlers[msgArray[0]]; ok {
		return auth.TryExecHandler(msg, handler.Level, handler.Handler)
	}
	if groupHandler, ok := GroupHandlers[msg.GroupInfo.GroupId]; ok {
		if handler, ok := groupHandler[msgArray[0]]; ok {
			return auth.TryExecHandler(msg, handler.Level, handler.Handler)
		}
	}
	for trigger, handler := range regexHandlers {
		exp := regexp.MustCompile(trigger)
		if exp.MatchString(msg.RawMsg) {
			return auth.TryExecHandler(msg, handler.Level, handler.Handler)
		}
	}
	if !msg.GroupInfo.IsGroupMsg && privateAllHandler != nil {
		return privateAllHandler(msg)
	}
	return nil
}

func RegisterHelpInform(triggerName string, category string, inform string) {
	if _, ok := HelpInforms[category]; !ok {
		HelpInforms[category] = []model.HelpInform{}
	}
	HelpInforms[category] = append(HelpInforms[category], model.HelpInform{
		Trigger: triggerName,
		Inform:  inform,
	})
}
