package sensitiveWordsMgr

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"

	"Framework/goroutineMgr"
	. "Framework/managecenterModel"
	"goutil/dfaUtil"
	"goutil/logUtil"
	"goutil/mathUtil"
	"goutil/webUtil"
	"goutil/zlibUtil"
)

// const GetForbidWordURL string = "http://10.253.0.186:10090/Query"
type ForbidWords struct {
	//游戏ID
	GameId int
	//屏蔽字
	Words string
}

// 请求屏蔽字库地址
const GetForbidWordURL string = "http://forbidword.7qule.com/Query"

var (
	mHashValue string
	mDFAUtil   *dfaUtil.DFAUtil
	mGameId    int
	rand       *mathUtil.Rand
	mGameOnly  bool = false
)

// 获取屏蔽字
func refreshSensitiveWord() error {
	//定义参数
	requestParamMap := make(map[string]string, 0)
	requestParamMap["GameId"] = strconv.Itoa(mGameId)
	requestParamMap["HashValue"] = mHashValue
	requestParamMap["DataType"] = "1"
	requestParamMap["IsResultCompressed"] = "true"
	if mGameOnly {
		requestParamMap["GameOnly"] = "true"
	}
	//data, _ := json.Marshal(requestParamMap)

	//请求url,请求头
	header := webUtil.GetFormHeader()
	transport := webUtil.NewTransport()
	transport.DisableKeepAlives = true
	transport = webUtil.GetTimeoutTransport(transport, 1000)

	statusCode, returnBytesTemp, err := webUtil.PostMapData(GetForbidWordURL, requestParamMap, header, transport)
	//statusCode, returnBytes, err := webUtil.PostMapData(GetForbidWordURL, requestParamMap, header, nil)
	if err != nil {
		logUtil.ErrorLog(fmt.Sprintf("获取敏感字出错，url:%s,错误信息为:%s", GetForbidWordURL, err))
		return err
	}
	if statusCode != 200 {
		logUtil.ErrorLog(fmt.Sprintf("获取敏感字出错，url:%s,错误码为:%d", GetForbidWordURL, statusCode))
		return err
	}

	//解压
	returnBytes, err := zlibUtil.Decompress(returnBytesTemp)
	if err != nil {
		logUtil.ErrorLog("返回结果解压失败")
		return err
	}

	// 解析返回值
	returnObj := new(ReturnObject)
	if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
		logUtil.ErrorLog(fmt.Sprintf("获取敏感字反序列化返回值出错，错误信息为：%s, str:%s", err, string(returnBytes)))
		return err
	}

	// 判断返回状态是否为成功
	if returnObj.Code != 0 {
		msg := fmt.Sprintf("获取敏感字出错，返回状态：%d，信息为：%s", returnObj.Code, returnObj.Message)
		logUtil.ErrorLog(msg)
		return errors.New(msg)
	} else if returnObj.Code == 0 && len(returnObj.HashValue) == 0 { //表示没有更新
		return nil
	}

	// 解析Data
	var tmpSensitiveWordList []*ForbidWords
	if data, ok := returnObj.Data.(string); !ok {
		msg := "获取敏感字出错，返回的数据不是string类型"
		logUtil.ErrorLog(msg)
		return errors.New(msg)
	} else {
		if err = json.Unmarshal([]byte(data), &tmpSensitiveWordList); err != nil {
			logUtil.ErrorLog(fmt.Sprintf("获取敏感字反序列化数据出错，错误信息为：%s", err))
			return err
		}
	}

	//缓存hasvalue
	mHashValue = returnObj.HashValue

	//获取敏感字数组
	var temWordArray []string
	for _, item := range tmpSensitiveWordList {
		temWordArray = append(temWordArray, strings.ToUpper(item.Words))
	}
	//dfa
	mDFAUtil = dfaUtil.NewDFAUtil(temWordArray)

	return nil
}

// 是否包含屏蔽字
func IsSensitiveWords(input string) (exist bool) {
	input = strings.ToUpper(input)
	exist = mDFAUtil.IsMatch(input)

	return
}

// 取出敏感字及开始位置
func SensitiveWords(input string) (words []string, pos []int, exist bool) {
	input2 := strings.ToUpper(input)
	inputRune := []rune(input)
	startIndexList, endIndexList := mDFAUtil.SearchSentence(input2)
	if len(startIndexList) > 0 {
		exist = true
		words = make([]string, 0, len(startIndexList))
		pos = make([]int, 0, len(startIndexList))
		for i := 0; i < len(startIndexList); i++ {
			start := startIndexList[i]
			end := endIndexList[i]
			words = append(words, string(inputRune[start:end+1]))
			pos = append(pos, start)
		}
	}

	return
}

// 取出敏感字及开始及结束位置
func SensitiveWordsEndStartPos(input string) (words []string, starts, ends []int, exist bool) {
	input2 := strings.ToUpper(input)
	inputRune := []rune(input)
	startIndexList, endIndexList := mDFAUtil.SearchSentence(input2)
	if len(startIndexList) > 0 {
		exist = true
		words = make([]string, 0, len(startIndexList))
		starts = startIndexList
		ends = endIndexList
		for i := 0; i < len(startIndexList); i++ {
			start := startIndexList[i]
			end := endIndexList[i]
			words = append(words, string(inputRune[start:end+1]))
			//pos = append(pos, start)
		}
	}

	return
}

// 根据用户输入的替换词替换敏感词
func ReplaceSendsitiveWords(input, replaceStr string) (newStr string) {
	words, _, _, exist := SensitiveWordsEndStartPos(input)
	newStr = input
	//如果不存在敏感词，则直接返回
	if !exist {
		return
	}
	//循环替换
	for _, sendsitiveWord := range words {
		newStr = strings.Replace(newStr, sendsitiveWord, replaceStr, -1)
	}

	return
}

// 判断服务器是否存在
func IfServerExists() (exist bool) {

	return
}

// 处理敏感字
func HandleSendsitiveWords(input string) (newStr string) {
	newStr = mDFAUtil.HandleWord(input, rune('*'))

	return
}

// 定时刷新敏感字库
func StartRefreshSensitiveWordListTread(gameId int) {
	rand = mathUtil.GetRand()
	mGameId = gameId
	// 定时刷新数据
	go func() {
		goroutineName := "sensitiveWordsMgr.StartRefreshSensitiveWordListTread"
		goroutineMgr.Monitor(goroutineName)
		defer goroutineMgr.ReleaseMonitor(goroutineName)

		for {
			// 刷新屏蔽字
			refreshSensitiveWord()

			// 每5分钟刷新一次
			time.Sleep(time.Duration(rand.GetRandRangeInt64(120, 300)) * time.Second)
		}
	}()
}

// 定时刷新敏感字库（排除公共字库，只刷新游戏内的）
func StartRefreshSensitiveListTreadExcludeComm(gameId int) {
	rand = mathUtil.GetRand()
	mGameId = gameId
	mGameOnly = true
	// 定时刷新数据
	go func() {
		goroutineName := "sensitiveWordsMgr.StartRefreshSensitiveWordListTread"
		goroutineMgr.Monitor(goroutineName)
		defer goroutineMgr.ReleaseMonitor(goroutineName)

		for {
			// 刷新屏蔽字
			refreshSensitiveWord()

			// 每5分钟刷新一次
			time.Sleep(time.Duration(rand.GetRandRangeInt64(120, 300)) * time.Second)
		}
	}()
}
