package client_proto

import (
	"os"
	"strings"
	"testing"
)

func TestClientProtoGen(t *testing.T) {
	// 生成根据proto类名获取对象实例的switch方法
	dir, err := os.ReadDir("./proto")
	if err != nil {
		panic(err)
	}
	protoObjNameList := make([]string, 0)
	for _, entry := range dir {
		if entry.IsDir() {
			continue
		}
		split := strings.Split(entry.Name(), ".")
		if len(split) < 2 || split[len(split)-1] != "proto" {
			continue
		}
		protoObjNameList = append(protoObjNameList, split[len(split)-2])
	}
	// 生成初始化cmdId和cmdName的方法
	clientCmdFile, err := os.ReadFile("./proto/client_cmd.csv")
	if err != nil {
		panic(err)
	}
	clientCmdData := string(clientCmdFile)
	clientCmdLineList := strings.Split(clientCmdData, "\n")
	// 生成代码文件
	fileData := "package client_proto\n"
	fileData += "\n"
	fileData += "import (\n"
	fileData += "\t\"hk4e/gate/client_proto/proto\"\n"
	fileData += ")\n"
	fileData += "\n"
	fileData += "func (c *ClientCmdProtoMap) LoadClientCmdIdAndCmdName() {\n"
	for _, clientCmdLine := range clientCmdLineList {
		if clientCmdLine == "" {
			continue
		}
		item := strings.Split(clientCmdLine, ",")
		if len(item) != 2 {
			panic("parse client cmd file error")
		}
		cmdName := item[0]
		cmdId := item[1]
		fileData += "\tc.clientCmdIdCmdNameMap[uint16(" + cmdId + ")] = \"" + cmdName + "\"\n"
		fileData += "\tc.clientCmdNameCmdIdMap[\"" + cmdName + "\"] = uint16(" + cmdId + ")\n"
	}
	fileData += "}\n"
	fileData += "\n"
	fileData += "func (c *ClientCmdProtoMap) GetClientProtoObjByName(protoObjName string) any {\n"
	fileData += "\tswitch protoObjName {\n"
	for _, protoObjName := range protoObjNameList {
		fileData += "\tcase \"" + protoObjName + "\":\n\t\treturn new(proto." + protoObjName + ")\n"
	}
	fileData += "\tdefault:\n"
	fileData += "\t\treturn nil\n"
	fileData += "\t}\n"
	fileData += "}\n"
	err = os.WriteFile("./client_proto_gen.go", []byte(fileData), 0644)
	if err != nil {
		panic(err)
	}
	// 处理枚举
	for _, entry := range dir {
		rawFileData, err := os.ReadFile("./proto/" + entry.Name())
		if err != nil {
			panic(err)
		}
		rawFileStr := string(rawFileData)
		rawFileLine := strings.Split(rawFileStr, "\n")
		newFileStr := ""
		for i := 0; i < len(rawFileLine); i++ {
			line := rawFileLine[i]
			newFileStr += line + "\n"
			if !strings.Contains(line, "enum") {
				continue
			}
			split := strings.Split(strings.TrimSpace(line), " ")
			if len(split) != 3 || split[0] != "enum" || split[2] != "{" {
				continue
			}
			enumName := split[1]
			// 从protocol/proto_hk4e下复制同名的枚举类替换掉原proto文件里的内容
			refEnum := FindEnumInDirFile("../../protocol/proto_hk4e", enumName)
			if refEnum == nil {
				continue
			}
			for _, ref := range refEnum {
				newFileStr += ref + "\n"
			}
			i++
			for {
				nextLine := rawFileLine[i]
				if !strings.Contains(nextLine, "}") {
					i++
				} else {
					newFileStr += nextLine + "\n"
					break
				}
			}
		}
		err = os.WriteFile("./proto/"+entry.Name(), []byte(newFileStr), 0644)
		if err != nil {
			panic(err)
		}
	}
}

func FindEnumInDirFile(path string, name string) (lineList []string) {
	dir, err := os.ReadDir(path)
	if err != nil {
		panic(err)
	}
	for _, entry := range dir {
		if entry.IsDir() {
			ret := FindEnumInDirFile(path+"/"+entry.Name(), name)
			if ret != nil {
				return ret
			}
			continue
		}
		fileData, err := os.ReadFile(path + "/" + entry.Name())
		if err != nil {
			panic(err)
		}
		fileStr := string(fileData)
		fileLine := strings.Split(fileStr, "\n")
		for i := 0; i < len(fileLine); i++ {
			line := fileLine[i]
			if !strings.Contains(line, "enum") {
				continue
			}
			split := strings.Split(strings.TrimSpace(line), " ")
			if len(split) != 3 || split[0] != "enum" || split[2] != "{" {
				continue
			}
			enumName := split[1]
			if enumName != name {
				continue
			}
			i++
			lineList := make([]string, 0)
			for {
				nextLine := fileLine[i]
				if !strings.Contains(nextLine, "}") {
					lineList = append(lineList, nextLine)
				} else {
					return lineList
				}
				i++
			}
		}
	}
	return nil
}
