// Package json_tool...
//
// Description : 动态构建json
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2021-03-10 10:26 下午
package json_tool

import (
	"encoding/json"
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"git.zhangdeman.cn/zhangdeman/gopkg/easylock"
	"github.com/pkg/errors"
)

const (
	// PathSplit json_tool 路径的分割符
	PathSplit = "."
)

// JSONode JSOM节点
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 10:33 下午 2021/3/10
type JSONode struct {
	Key              string      // json_tool key
	Value            interface{} // 对应的值
	Child            []*JSONode  // 子节点
	IsRoot           bool        // 是否根节点
	IsHasLastBrother bool        // 在此之后是否有其他兄弟节点
	IsSlice          bool        // 是否是list
	IsIndexNode      bool        // 是否是slice的索引节点
	Sort             int         // 此属性用于 slice解析,保证最终排序是对的
	IsComplex        bool        // 是否为复杂数据类型
	IsString         bool        // 是否为字符串
}

// NewDynamicJSON 获取JSON实例
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 10:36 下午 2021/3/10
func NewDynamicJSON() *DynamicJSON {
	exp, _ := regexp.Compile(`\[(\d*?)]`)
	return &DynamicJSON{
		root: &JSONode{
			Key:    "",
			Value:  nil,
			Child:  nil,
			IsRoot: true,
		},
		nodeCnt:  0,
		lock:     easylock.NewLock(),
		sliceExp: exp,
	}
}

// DynamicJSON 动态json
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 11:03 下午 2021/3/10
type DynamicJSON struct {
	root     *JSONode          // 节点数
	nodeCnt  int               // 节点数量
	lock     easylock.EasyLock // 锁
	sliceExp *regexp.Regexp    // 抽取slice索引的正则
}

// SetValue 设置节点值,如果节点不存在,创建;如果已存在,更新, 多级key使用, value 必须是基础数据类型, 如果是结构体, 需要继续添加path,多级path使用.分割
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 10:45 下午 2021/3/10
func (dj *DynamicJSON) SetValue(path string, value interface{}, isComplexType bool) {
	pathList := strings.Split(path, PathSplit)
	searchRoot := dj.root
	parent := dj.root
	for keyIndex, key := range pathList {
		searchRoot = dj.search(searchRoot, key)
		if nil != searchRoot {
			// 查询到结果,更新值
			searchRoot.Value = value
			parent = searchRoot
			continue
		}
		var val interface{}
		if keyIndex == len(pathList)-1 {
			val = value
		}
		_ = dj.createNode(parent, key, val, isComplexType)
		if len(parent.Child) > 0 {
			searchRoot = parent.Child[len(parent.Child)-1]
			parent = parent.Child[len(parent.Child)-1]
		}
	}
}

// String 获取字符串的格式JSON
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2:16 下午 2021/3/11
func (dj *DynamicJSON) String() string {
	tplList := make([]string, 0)
	valList := make([]interface{}, 0)
	tplListResult, valListResult := dj.buildTpl(dj.root, &tplList, &valList)
	return fmt.Sprintf(strings.Join(*tplListResult, ""), *valListResult...)
}

// Map 转化为map
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:59 上午 2021/9/9
func (dj *DynamicJSON) Map() (map[string]interface{}, error) {
	var res map[string]interface{}
	err := json.Unmarshal([]byte(dj.String()), &res)
	return res, err
}

// Slice 转化为slice
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:59 上午 2021/9/9
func (dj *DynamicJSON) Slice() ([]interface{}, error) {
	var res []interface{}
	err := json.Unmarshal([]byte(dj.String()), &res)
	return res, err
}

// ParseWithReceiver 使用指定结构解析
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 10:01 上午 2021/9/9
func (dj *DynamicJSON) ParseWithReceiver(receiver interface{}) error {
	if nil == receiver {
		return errors.New("receiver is nil")
	}
	return json.Unmarshal([]byte(dj.String()), receiver)
}

// buildTpl 构建json模版与绑定数据
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 4:38 下午 2021/3/11
func (dj *DynamicJSON) buildTpl(root *JSONode, tplList *[]string, valList *[]interface{}) (*[]string, *[]interface{}) {
	if nil == root {
		return tplList, valList
	}
	startSymbol := dj.getStartSymbol(root)
	endSymbol := dj.getEndSymbol(root)
	valFormat := dj.getValFormat(root)
	// key := "\"" + root.Key + "\""
	if !root.IsIndexNode {
		if len(root.Child) > 0 {
			*tplList = append(*tplList, startSymbol)
		} else {
			*tplList = append(*tplList, valFormat)
			*valList = append(*valList, root.Value)
			return tplList, valList
		}
	} else {
		if len(root.Child) == 0 {
			*tplList = append(*tplList, valFormat)
			*valList = append(*valList, root.Value)
		} else {
			*tplList = append(*tplList, startSymbol)
		}
	}
	for _, node := range root.Child {
		dj.buildTpl(node, tplList, valList)
	}
	*tplList = append(*tplList, endSymbol)

	return tplList, valList
}

// getValFormat 构建值得占位符
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:49 下午 2021/3/13
func (dj *DynamicJSON) getValFormat(root *JSONode) string {
	key := fmt.Sprintf("\"%s\"", root.Key)
	if !root.IsIndexNode {
		if len(root.Child) > 0 {
			// 还有自节点的情况下,不需要占位符
			return ""
		}

		if root.IsHasLastBrother {
			if root.IsString {
				return key + ":\"%v\","
			}
			return key + ":%v,"
		}
		if root.IsString {
			return key + ":\"%v\""
		}
		return key + ":%v"
	}

	if len(root.Child) > 0 {
		// 是list的索引节点,且有子节点
		return ""
	}
	if root.IsHasLastBrother {
		if root.IsString {
			return "\"%v\","
		}
		return "%v,"
	}
	if root.IsString {
		return "\"%v\""
	}
	return "%v"
}

// getStartSymbol 计算起始的符号
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:21 下午 2021/3/13
func (dj *DynamicJSON) getStartSymbol(root *JSONode) string {
	if nil == root {
		return "{"
	}

	if root.IsRoot {
		if root.IsSlice {
			return "["
		}
		return "{"
	}
	key := fmt.Sprintf("\"%s\"", root.Key)
	if !root.IsIndexNode {
		if len(root.Child) > 0 {

			if root.IsSlice {
				return key + ":["
			} else {
				return key + ":{"
			}

		}
		return ""
	}
	if len(root.Child) > 0 {
		return "{"
	}
	return ""
}

// getEndSymbol 计算结束的符号
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:21 下午 2021/3/13
func (dj *DynamicJSON) getEndSymbol(root *JSONode) string {
	if nil == root {
		return "}"
	}
	if !root.IsIndexNode {
		if root.IsHasLastBrother {
			return "},"
		}
		if root.IsSlice {
			return "]"
		} else {
			return "}"
		}

	}
	if len(root.Child) > 0 {
		if root.IsHasLastBrother {
			return "},"
		}
		return "}"

	}
	return ""
}

// Search 搜索一个key TODO : 优化
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 11:19 下午 2021/3/10
func (dj *DynamicJSON) search(root *JSONode, key string) *JSONode {
	if root == nil {
		return nil
	}
	for _, node := range root.Child {
		if node == nil {
			continue
		}
		if node.Key == key {
			return node
		}
	}
	return nil
}

// createNode 创建新的节点
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 10:57 下午 2021/3/10
func (dj *DynamicJSON) createNode(parent *JSONode, key string, value interface{}, isComplexType bool) error {
	if nil == parent {
		return errors.New("create node error : parent id nil")
	}
	_ = dj.lock.Lock()
	if parent.Child == nil {
		parent.Child = make([]*JSONode, 0)
	}
	if len(parent.Child) > 0 {
		// 存在子节点,设置当前子节点还有其他兄弟节点
		parent.Child[len(parent.Child)-1].IsHasLastBrother = true
	}

	newNode := &JSONode{
		Key:              key,
		Value:            value,
		Child:            make([]*JSONode, 0),
		IsRoot:           false,
		IsHasLastBrother: false,
		IsComplex:        isComplexType,
		IsString:         false,
	}
	if !isComplexType {
		switch value.(type) {
		case string:
			newNode.IsString = true
		}
	}
	parent.IsSlice, newNode.Sort = dj.extraSliceIndex(key)
	if parent.IsSlice {
		newNode.IsIndexNode = true
	}
	parent.Child = append(parent.Child, newNode)
	dj.nodeCnt++
	_ = dj.lock.Unlock()
	return nil
}

// extraSliceIndex 抽取slice索引
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:37 下午 2021/3/11
func (dj *DynamicJSON) extraSliceIndex(key string) (bool, int) {
	if len(key) < 3 {
		// slice 至少是 [1] 格式
		return false, 0
	}

	if !strings.HasPrefix(key, "[") || !strings.HasSuffix(key, "]") {
		return false, 0
	}
	// 不用正则,直接字符串处理
	strByte := []byte(key)
	index, err := strconv.Atoi(string(strByte[1 : len(strByte)-1]))
	if nil != err {
		return false, 0
	}
	return true, index
}