// Package json2go ...
//
// Description : json2go ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2021-11-09 3:44 下午
package json2go

import (
	"fmt"
	"strings"

	"git.zhangdeman.cn/zhangdeman/gopkg/util"

	"github.com/pkg/errors"
	"github.com/tidwall/gjson"
)

var (
	// structName 结构体名称
	structName = "Automatic"
)

// NewJSON2GO ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 6:13 下午 2021/11/9
func NewJSON2GO(name string) *JSON2GO {
	if len(name) == 0 {
		name = structName
	}
	return &JSON2GO{
		structName: name,
	}
}

// JSON2GO ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 6:12 下午 2021/11/9
type JSON2GO struct {
	structName string
	result     string
}

// Parse ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 3:44 下午 2021/11/9
func (jg *JSON2GO) Parse(inputJSON string) (string, error) {
	if !gjson.Valid(inputJSON) {
		return "", errors.New("input json is invalid")
	}
	parseResult := gjson.Parse(inputJSON)
	if parseResult.IsArray() {
		jg.append("type " + jg.structName + " [] \n")
		jg.parseArray("", parseResult)
	} else {
		jg.append("type " + jg.structName + " struct { \n")
		jg.parseObject("", parseResult)
	}
	jg.append("}")
	return jg.result, nil
}

// parseArray 解析array
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 4:37 下午 2021/11/9
func (jg *JSON2GO) parseArray(key string, parseResult gjson.Result) {
	// 先遍历一遍确认所有数据类型都相同
	dataType := ""
	if len(parseResult.Array()) > 0 {
		for _, item := range parseResult.Array() {
			if len(dataType) == 0 {
				dataType = jg.getDataType(item)
				continue
			}
			currentType := jg.getDataType(item)
			if currentType != dataType {
				if (dataType == "int64" && currentType == "float64") || (dataType == "float64" && currentType == "int64") {
					dataType = "float64"
					continue
				}
				// 不是所有数据类型都一致
				if len(key) == 0 {
					jg.result += "interface{}"
					return
				}
				jg.append(jg.buildField("[]interface{}", key))
				return
			}
		}
	} else {
		dataType = "interface{}"
	}
	// 对象,重新
	if dataType == "object" {
		instance := NewJSON2GO("")
		r, _ := instance.Parse(parseResult.Array()[0].String())
		dataType = strings.Replace(strings.Replace(r, "type", "", 1), "Automatic", "", 1)
	}

	// 所有数据类型都一致
	if len(key) == 0 {
		jg.append("[]" + dataType)
	} else {
		jg.append(jg.buildField("[]"+dataType, key))
	}
}

// parseObject 解析object
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 4:37 下午 2021/11/9
func (jg *JSON2GO) parseObject(key string, parseResult gjson.Result) string {
	if len(key) > 0 {
		jg.result += util.SnakeCaseToCamel(key) + " struct { \n"
	}
	for k, v := range parseResult.Map() {
		if v.IsObject() {
			jg.parseObject(k, v)
		} else if v.IsArray() {
			jg.parseArray(k, v)
		} else {
			jg.append(jg.buildField(jg.getDataType(v), k))
		}
	}
	if len(key) > 0 {
		jg.append(" } `json:\"" + key + "\"`\n")
	}
	return ""
}

// getDataType 获取数据类型
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 8:14 下午 2021/11/9
func (jg *JSON2GO) getDataType(val gjson.Result) string {
	switch val.Type {
	case gjson.True:
		fallthrough
	case gjson.False:
		return "bool"
	case gjson.Null:
		return "map[string]interface{}"
	case gjson.String:
		return "string"
	case gjson.Number:
		tmpVal := fmt.Sprintf("%v", val.Num)
		if strings.Contains(tmpVal, ".") {
			return "float64"
		}
		return "int64"
	case gjson.JSON:
		return "object"
	default:
		return "interface{}"
	}
}

// buildField 构建字段
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:20 下午 2021/11/9
func (jq *JSON2GO) buildField(fieldType string, jsonTag string) string {
	return util.SnakeCaseToCamel(jsonTag) + " " + fieldType + " `json:\"" + jsonTag + "\"`\n"
}

// append 构建result
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:19 下午 2021/11/9
func (jq *JSON2GO) append(appendStr string) {
	jq.result += appendStr
}