package main

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/tealeg/xlsx"
	"mongo.games.com/goserver/core"
)

type SheetColumnMetaStruct struct {
	ColName  string
	ColType  int
	CTString string
	IsArray  bool
}

type SheetMetaStruct struct {
	AbsPath   string
	FileName  string
	ProtoName string
	Cols      []*SheetColumnMetaStruct
}

const (
	INTTYPE         string = "(int)"
	INT64TYPE       string = "(int64)"
	STRTYPE                = "(str)"
	ARRINTTYPE             = "(arrint)"
	ARRINT64TYPE           = "(arrint64)"
	ARRSTRTYPE             = "(arrstr)"
	INTTYPE_PROTO          = "int32"
	INT64TYPE_PROTO        = "int64"
	STRTYPE_PROTO          = "string"
)

var templates *template.Template

func main() {

	defer core.ClosePackages()
	core.LoadPackages("config.json")

	smsMap := make(map[string]*SheetMetaStruct)
	for xlsxFileName, xlsxFilePath := range XlsxFiles {
		xlsxFile, err := xlsx.OpenFile(xlsxFilePath)
		if err != nil {
			fmt.Println("excel file open error:", err, " filePath:", xlsxFilePath)
			continue
		}

		for _, sheet := range xlsxFile.Sheets {
			sms := &SheetMetaStruct{
				AbsPath:   xlsxFilePath,
				FileName:  xlsxFileName,
				ProtoName: strings.TrimSuffix(xlsxFileName, ".xlsx"),
				Cols:      make([]*SheetColumnMetaStruct, 0, sheet.MaxCol)}

			for _, row := range sheet.Rows {
				for _, cell := range row.Cells {
					s := cell.String()
					if strings.HasSuffix(s, INTTYPE) {
						sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{strings.TrimSuffix(s, INTTYPE), 1, INTTYPE_PROTO, false})
					} else if strings.HasSuffix(s, STRTYPE) {
						sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{strings.TrimSuffix(s, STRTYPE), 2, STRTYPE_PROTO, false})
					} else if strings.HasSuffix(s, ARRINTTYPE) {
						sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{strings.TrimSuffix(s, ARRINTTYPE), 3, INTTYPE_PROTO, true})
					} else if strings.HasSuffix(s, ARRSTRTYPE) {
						sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{strings.TrimSuffix(s, ARRSTRTYPE), 4, STRTYPE_PROTO, true})
					} else if strings.HasSuffix(s, INT64TYPE) {
						sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{strings.TrimSuffix(s, INT64TYPE), 5, INT64TYPE_PROTO, false})
					} else if strings.HasSuffix(s, ARRINT64TYPE) {
						sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{strings.TrimSuffix(s, ARRINT64TYPE), 6, INT64TYPE_PROTO, true})
					}
				}
				break //only fetch first row
			}

			smsMap[sms.ProtoName] = sms
			break //only fetch first sheet
		}
	}

	geneProto(smsMap)
}

func geneProto(xlsxs map[string]*SheetMetaStruct) {
	if xlsxs == nil {
		return
	}

	geneAgcHelper(xlsxs)       //生成 xlsx转二进制文件
	geneDataStructProto(xlsxs) //生成 xlsx转protobuf结构文件
	//geneDataSingleStructProto(xlsxs)
	//geneChhDataMgrHeader(xlsxs)//生成 c头文件
	//geneCppDataMgrHeader(xlsxs)//生成 c源文件
	//copyNoDataProtoToLua()
	for _, val := range xlsxs {
		genGoDataMgr(val) //生成 go对象文件
		genTsDataMgr(val) //生成 ts对象文件
	}
}

func geneAgcHelper(xlsxs map[string]*SheetMetaStruct) {
	dm := map[string]interface{}{
		"data":  xlsxs,
		"opath": filepath.Join(Config.WorkPath, Config.DataPath),
	}
	outputHelper := bytes.NewBuffer(nil)
	err := templates.ExecuteTemplate(outputHelper, "agc", dm)
	if err != nil {
		fmt.Println("geneProto ExecuteTemplate error:", err)
		return
	}

	helperGoFile := filepath.Join(Config.WorkPath, Config.ConvertToolPath, "agc.go")
	err = os.WriteFile(helperGoFile, outputHelper.Bytes(), os.ModePerm)
	if err != nil {
		fmt.Println("geneProto WriteFile error:", err)
		return
	}
}

func geneDataStructProto(xlsxs map[string]*SheetMetaStruct) {

	outputHelper := bytes.NewBuffer(nil)
	err := templates.ExecuteTemplate(outputHelper, "gpb", xlsxs)
	if err != nil {
		fmt.Println("geneDataStructProto ExecuteTemplate error:", err)
		return
	}

	protoFile := filepath.Join(Config.WorkPath, Config.ProtoPath, Config.ProtoFile)
	err = os.WriteFile(protoFile, outputHelper.Bytes(), os.ModePerm)
	if err != nil {
		fmt.Println("geneDataStructProto error:", err)
	}
}

func geneDataSingleStructProto(xlsxs map[string]*SheetMetaStruct) {
	for k, v := range xlsxs {
		outputHelper := bytes.NewBuffer(nil)
		err := templates.ExecuteTemplate(outputHelper, "gpb_single", v)
		if err != nil {
			fmt.Println("geneDataSingleStructProto ExecuteTemplate error:", err)
			return
		}

		protoFile := filepath.Join(Config.WorkPath, Config.ProtoLuaPath, strings.ToLower(k)+".proto")
		err = os.WriteFile(protoFile, outputHelper.Bytes(), os.ModePerm)
		if err != nil {
			fmt.Println("geneDataSingleStructProto error:", err)
		}
	}
}

func genGoDataMgr(sms *SheetMetaStruct) {
	if sms == nil {
		return
	}

	outputHelper := bytes.NewBuffer(nil)
	err := templates.ExecuteTemplate(outputHelper, "gpb_mgr", sms)
	if err != nil {
		fmt.Println("genGoDataMgr ExecuteTemplate error:", err)
		return
	}
	opath := filepath.Join(Config.WorkPath, Config.GoFilePath, strings.ToLower(fmt.Sprintf("%v.go", sms.ProtoName)))
	err = os.WriteFile(opath, outputHelper.Bytes(), os.ModePerm)
	if err != nil {
		fmt.Println("genGoDataMgr WriteFile error:", err)
		return
	}
}

// 生成ts类模板
func genTsDataMgr(sms *SheetMetaStruct) {
	if sms == nil {
		return
	}

	outputHelper := bytes.NewBuffer(nil)
	err := templates.ExecuteTemplate(outputHelper, "gpb_mgr_ts", sms)
	if err != nil {
		fmt.Println("genTsDataMgr ExecuteTemplate error:", err)
		return
	}
	//opath := filepath.Join(Config.WorkPath, Config.TsFilePath, strings.ToLower(fmt.Sprintf("%v.ts", sms.ProtoName)))
	opath := fmt.Sprintf("%v/%v", Config.TsFilePath, strings.ToLower(fmt.Sprintf("%v.ts", sms.ProtoName)))
	err = os.WriteFile(opath, outputHelper.Bytes(), os.ModePerm)
	if err != nil {
		fmt.Println("genTsDataMgr WriteFile error:", err)
		return
	}
}

func geneChhDataMgrHeader(xlsxs map[string]*SheetMetaStruct) {
	dm := map[string]interface{}{
		"data": xlsxs,
	}
	outputHelper := bytes.NewBuffer(nil)
	err := templates.ExecuteTemplate(outputHelper, "gpb_mgr_h", dm)
	if err != nil {
		fmt.Println("geneProto ExecuteTemplate error:", err)
		return
	}

	helperChhFile := filepath.Join(Config.WorkPath, Config.CppFilePath, "DataMgrAgc.h")
	err = os.WriteFile(helperChhFile, outputHelper.Bytes(), os.ModePerm)
	if err != nil {
		fmt.Println("geneProto WriteFile error:", err)
		return
	}
}

func geneCppDataMgrHeader(xlsxs map[string]*SheetMetaStruct) {
	dm := map[string]interface{}{
		"data": xlsxs,
	}
	outputHelper := bytes.NewBuffer(nil)
	err := templates.ExecuteTemplate(outputHelper, "gpb_mgr_c", dm)
	if err != nil {
		fmt.Println("geneProto ExecuteTemplate error:", err)
		return
	}

	helperChhFile := filepath.Join(Config.WorkPath, Config.CppFilePath, "DataMgrAgc.cpp")
	err = os.WriteFile(helperChhFile, outputHelper.Bytes(), os.ModePerm)
	if err != nil {
		fmt.Println("geneProto WriteFile error:", err)
		return
	}
}

func copyNoDataProtoToLua() {
	protoFile := filepath.Join(Config.WorkPath, Config.ProtoPath)
	rootdir, pathopen := os.Open(protoFile)
	if pathopen != nil {
		fmt.Println("Path open error.")
	} else {
		files, _ := rootdir.Readdir(0)
		for _, fi := range files {
			if strings.HasSuffix(fi.Name(), ".proto") && !strings.Contains(fi.Name(), "pbdata.proto") {
				datas, err := os.ReadFile(filepath.Join(Config.WorkPath, Config.ProtoPath, fi.Name()))
				if err == nil {
					strContent := string(datas[:])
					strContent = strings.Replace(strContent, `"protocol/`, `"`, -1)
					dest := filepath.Join(Config.WorkPath, Config.ProtoLuaPath, fi.Name())
					fmt.Println("==========dest", dest)
					os.WriteFile(dest, []byte(strContent), os.ModePerm)
				} else {
					fmt.Println(err)
				}
			}

		}
	}
}
