// Package msg
// 一个错误编号表示唯一一个错误发生地点
// 错误编号格式：顺序号*1000000 + 程序编号*1000 + 模块编号
// 模块内函数发生错误，编号：1-100
// 特定错误，编号：101-200
// 其他地方发生错误，占用地址列表
// 1、
package msg

import "fmt"

// ErrorCode 结构体表示错误编码
type ErrorCode struct {
	ProgramID int
	ModuleID  int
}

const (
	ServerTypeLogin = 1
	ServerTypeGate  = 2
	ServerTypeWorld = 3

	ServerTypeAll = 999 // 所有服务器
)

const (
	GateModleGame = 1
	GateModleGate = 2
	GateModlePush = 3

	WorldModleDb         = 1
	WorldModleGame       = 2
	WorldModleGate       = 3
	WorldModleSystemData = 4

	AllModelAll = 999 // 所有模块
)

// 对象类型 1000种
const (
	ErrObjectParam     = 1
	ErrObjectPlayer    = 2
	ErrObjectConfig    = 3
	ErrObjectCondition = 4
	ErrObjectTarget    = 5
	ErrObjectItem      = 6
	ErrObjectResult    = 7

	ErrObjectHero      = 9
	ErrObjectTreasures = 10
	ErrObjectChapter   = 11
	ErrObjectReward    = 12
	ErrObjectStam      = 13

	ErrObjectSystem = 90
	ErrObjectDb     = 91
	ErrObjectRedis  = 92

	ErrObjectMax = 999
)

// 每个对象100种状态
// 定义10个常用状态
const (
	ErrStatusInvalid   = 91 // 无效
	ErrStatusNotFound  = 92 // 未发现
	ErrStatusNotEnough = 93 // 不够
	ErrStatusError     = 94 // 错误
	ErrStatusOverstep  = 95 // 超出
)

const (
	Multiple100 = 100

	// 全局参数 一般不要用，防止出现问题定位不到在所在程序及位置
	// 999 999 001 0000 - 999 999 999 9999
	ErrPlayerNoToken    = 999_999_000_0000 + errPlayerNoToken*100
	ErrPlayerBanLogin   = 999_999_000_0000 + errPlayerBanLogin*100
	ErrPlayerOtherLogin = 999_999_000_0000 + errPlayerOtherLogin*100

	ErrSystemUpgrade    = 999_999_000_0000 + ErrObjectSystem*10000 + 1*100
	ErrSystemFull       = 999_999_000_0000 + ErrObjectSystem*10000 + 2*100
	ErrSystemFoundCheat = 999_999_000_0000 + ErrObjectSystem*10000 + 3*100

	// 请求参数 100
	ErrParamInvalid = ErrObjectParam*Multiple100 + ErrStatusInvalid

	// 玩家 200
	errPlayerBanLogin   = ErrObjectPlayer*Multiple100 + 1
	errPlayerOtherLogin = ErrObjectPlayer*Multiple100 + 2
	ErrPlayerNotFound   = ErrObjectPlayer*Multiple100 + ErrStatusNotFound
	errPlayerNoToken    = ErrObjectPlayer*Multiple100 + 3

	// 道具 300
	ErrItemNotFound  = ErrObjectItem*Multiple100 + ErrStatusNotFound
	ErrItemNotEnough = ErrObjectItem*Multiple100 + ErrStatusNotEnough

	// 目标
	ErrTargetNotFound = ErrObjectTarget*Multiple100 + ErrStatusNotFound

	// 配置
	ErrConfigNotFound = ErrObjectConfig*Multiple100 + ErrStatusNotFound
	ErrConfigError    = ErrObjectConfig*Multiple100 + ErrStatusError

	// 条件
	ErrConditionNotEnough = ErrObjectCondition*Multiple100 + ErrStatusNotEnough

	// 结果
	ErrResultError = ErrObjectResult*Multiple100 + ErrStatusError

	// 英雄 400
	ErrHeroNotFound = ErrObjectHero*Multiple100 + ErrStatusNotFound

	// 宝物 500
	ErrTreasuresNotFound = ErrObjectTreasures*Multiple100 + ErrStatusNotFound

	// 数据库 600
	ErrDBExec    = ErrObjectDb*Multiple100 + 1
	ErrDBLoadNil = ErrObjectDb*Multiple100 + 2

	// redis 700
	ErrRedisExec = ErrObjectRedis*Multiple100 + 1

	// 章节
	ErrChapterNotFound = ErrObjectChapter*Multiple100 + ErrStatusNotFound

	//奖励
	ErrRewardNotFound   = ErrObjectReward*Multiple100 + ErrStatusNotFound
	ErrRewardIsReceived = ErrObjectReward*Multiple100 + 1 // 已领取

	//体力
	ErrStamOverstep = ErrObjectStam*Multiple100 + ErrStatusOverstep

	// 配置
	// ErrConfigMaxOnline = ErrObjectConfig*Multiple100 + 1

	ErrMaxTypeMaxStatus = ErrObjectMax*100 + 99 // 99900+99 = 999_99
	ErrMaxVal           = 999*1000_000_0000 + 999*1000_0000 + 999*10000 + 99*100 + 99
)

// 每种状态在同一个函数种可以使用100次，需要序号递增

// initErrorCodes 是一个包级初始化函数，用于设置程序编号和模块编号
// login 1:
// world 2: db:1; game:2; gate:3; systemdata:4
// gate 3:
func InitErrorCodes(programID, moduleID int) *ErrorCode {
	errorCodes := new(ErrorCode)
	errorCodes.ProgramID = programID
	errorCodes.ModuleID = moduleID
	return errorCodes
}

// GenerateErrorCode 生成错误编号，只需要提供顺序号
func (ec *ErrorCode) GenerateErrorCode(errObj int, errStatus int, seq int) int {
	return ec.ProgramID*1000_000_0000 + ec.ModuleID*1000_0000 + errObj*10000 + errStatus*100 + seq
}

// 支持输入格式
// ojbstatus
// objstatus,seq
//obj,status,seq
// promodelobjstatusseq
// promodelobjstatusseq,seq
func (ec *ErrorCode) CalcErrorCode(objStatusSeq ...int) int {
	num := len(objStatusSeq)
	switch num {
	case 0:
		return 0
	case 1:
		// objstatus
		// promodelobjstatusseq
		if objStatusSeq[0] > ErrObjectMax*10000 {
			return objStatusSeq[0]
		}
		return ec.GenerateErrorCode(objStatusSeq[0]/100, (objStatusSeq[0] % 100), 0)
	case 2:
		// objstatus,seq
		// promodelobjstatusseq,seq
		if objStatusSeq[0] > ErrObjectMax*10000 {
			return objStatusSeq[0] + objStatusSeq[1]
		}
		return ec.GenerateErrorCode(objStatusSeq[0]/100, (objStatusSeq[0] % 100), objStatusSeq[1])
	case 3:
		return ec.GenerateErrorCode(objStatusSeq[0], objStatusSeq[1], objStatusSeq[2])
	default:
		return 0
	}
}

func (ec *ErrorCode) PrintError(errCode int, errMsg string) {
	errCode2 := ec.CalcErrorCode(errCode)
	// code := (errCode2 % 1000_0000) / 100
	// fmt.Printf("%v-%v: %v %s\n", errCode2, errCode2+99, code, errMsg)
	fmt.Printf("%v: %s\n", errCode2, errMsg)
}

func PrintErrorCode() {

	errorEncoder1 := InitErrorCodes(ServerTypeGate, GateModleGame)
	errorEncoder1.PrintError(ErrParamInvalid, "参数错误")
	errorEncoder1.PrintError(ErrPlayerBanLogin, "禁止登录")
	errorEncoder1.PrintError(ErrPlayerOtherLogin, "异地登录")
	errorEncoder1.PrintError(ErrPlayerNotFound, "玩家未登录")
	errorEncoder1.PrintError(ErrPlayerNoToken, "玩家凭证不存在")

	errorEncoder2 := InitErrorCodes(ServerTypeWorld, WorldModleGame)
	errorEncoder2.PrintError(ErrItemNotEnough, "道具不足")
	errorEncoder2.PrintError(ErrItemNotFound, "道具不存在")
	errorEncoder2.PrintError(ErrHeroNotFound, "英雄不存在")
	errorEncoder2.PrintError(ErrTreasuresNotFound, "宝物不存在")
	errorEncoder2.PrintError(ErrDBExec, "数据库错误")
	errorEncoder2.PrintError(ErrDBLoadNil, "数据库加载错误")
	errorEncoder2.PrintError(ErrRedisExec, "缓存错误")

	errorEncoder2.PrintError(ErrTargetNotFound, "目标未发现")
	errorEncoder2.PrintError(ErrConfigNotFound, "配置未发现")
	errorEncoder2.PrintError(ErrConditionNotEnough, "条件不满足")

	errorEncoder1.PrintError(ErrPlayerNoToken, "玩家凭证不存在")
	errorEncoder1.PrintError(ErrPlayerBanLogin, "禁止登录")
	errorEncoder1.PrintError(ErrPlayerOtherLogin, "异地登录")
	errorEncoder1.PrintError(ErrSystemUpgrade, "系统维护")
	errorEncoder1.PrintError(ErrSystemFull, "服务器满")
	errorEncoder1.PrintError(ErrSystemFoundCheat, "数据异常")

	// 20010019100:参数错误
	// 20010020100:禁止登录
	// 20010020200:异地登录
	// 20010029200:玩家未登录
	// 20010020300:玩家凭证不存在
	// 20010020400:达到最大在线数
	// 30020030100:道具不足
	// 30020039200:道具不存在
	// 30020049200:英雄不存在
	// 30020059200:宝物不存在
	// 30020060100:数据库错误
	// 30020060200:数据库加载错误
	// 30020070100:缓存错误
}
