package main

import (
	"fmt"
	"os"
	"strings"
)

type permDecl struct {
	Code string
	Name string
}

type routePermDecl struct {
	Method   string
	Path     string
	PermCode string
	DataCode string
}

type fieldPermMap struct {
	Request  map[string]string // json字段名 → permCode
	Response map[string]string // json字段名 → permCode
}

type collectResult struct {
	perms      []permDecl
	routePerms []routePermDecl
	fieldPerms map[string]fieldPermMap // "METHOD /path" → fieldPermMap
}

func collect(input *PluginInput) *collectResult {
	seen := make(map[string]bool)
	result := &collectResult{
		fieldPerms: make(map[string]fieldPermMap),
	}

	if input == nil || input.Api == nil {
		return result
	}

	// 建立类型名 → TypeDef 的索引，用于展开嵌套类型
	typeIndex := make(map[string]*TypeDef, len(input.Api.Types))
	for i := range input.Api.Types {
		typeIndex[input.Api.Types[i].RawName] = &input.Api.Types[i]
	}

	addPerm := func(code, name string) {
		if seen[code] || code == "" {
			return
		}
		seen[code] = true
		if name == "" {
			name = generatePermName(code)
		}
		result.perms = append(result.perms, permDecl{Code: code, Name: name})
	}

	for _, group := range input.Api.Service.Groups {
		for _, route := range group.Routes {
			method := strings.ToUpper(route.Method)
			path := route.Path
			key := method + " " + path

			permCode := ""
			permName := ""
			if route.AtDoc.Properties != nil {
				permCode = route.AtDoc.Properties["perm"]
				permName = route.AtDoc.Properties["summary"]
			}

			if permCode == "" {
				fmt.Fprintf(os.Stderr, "WARN: handler %s (%s %s) has no perm declaration, treated as public\n",
					route.Handler, method, path)
				continue
			}

			addPerm(permCode, permName)

			dataCode := apiToDataCode(permCode)
			if dataCode != "" {
				addPerm(dataCode, "")
			}

			result.routePerms = append(result.routePerms, routePermDecl{
				Method:   method,
				Path:     path,
				PermCode: permCode,
				DataCode: dataCode,
			})

			fm := fieldPermMap{
				Request:  make(map[string]string),
				Response: make(map[string]string),
			}

			if route.RequestType != nil {
				for jsonField, permTag := range extractFieldPermsDeep(route.RequestType, typeIndex) {
					fm.Request[jsonField] = permTag
					addPerm(permTag, "")
				}
			}

			if route.ResponseType != nil {
				for jsonField, permTag := range extractFieldPermsDeep(route.ResponseType, typeIndex) {
					fm.Response[jsonField] = permTag
					addPerm(permTag, "")
				}
			}

			if len(fm.Request) > 0 || len(fm.Response) > 0 {
				result.fieldPerms[key] = fm
			}
		}
	}

	return result
}

// extractFieldPermsDeep 递归展开嵌套类型，提取所有 perm tag
func extractFieldPermsDeep(t *TypeDef, typeIndex map[string]*TypeDef) map[string]string {
	result := make(map[string]string)
	if t == nil {
		return result
	}
	collectFieldPerms(t.Members, typeIndex, result)
	return result
}

func collectFieldPerms(members []Member, typeIndex map[string]*TypeDef, result map[string]string) {
	for _, m := range members {
		jsonName := extractTagValue(m.Tag, "json")
		if jsonName == "" {
			jsonName = m.Name
		}

		permCode := extractTagValue(m.Tag, "perm")
		if permCode != "" {
			result[jsonName] = permCode
			continue
		}

		// 没有 perm tag，尝试展开嵌套类型（去掉 [] 前缀）
		rawName := strings.TrimPrefix(m.Type.RawName, "[]")
		if nested, ok := typeIndex[rawName]; ok && len(nested.Members) > 0 {
			collectFieldPerms(nested.Members, typeIndex, result)
		}
	}
}

// extractTagValue 从 struct tag 字符串中提取指定 key 的值
// tag 格式：`json:"username" perm:"data:user:email:write"`
func extractTagValue(tag, key string) string {
	tag = strings.Trim(tag, "`")
	search := key + `:"`
	idx := strings.Index(tag, search)
	if idx == -1 {
		return ""
	}
	rest := tag[idx+len(search):]
	end := strings.Index(rest, `"`)
	if end == -1 {
		return ""
	}
	val := rest[:end]
	// 取 json tag 的第一段（去掉 omitempty 等）
	if key == "json" {
		val = strings.Split(val, ",")[0]
		if val == "-" {
			return ""
		}
	}
	return val
}

func apiToDataCode(apiCode string) string {
	if !strings.HasPrefix(apiCode, "api:") {
		return ""
	}
	return "data:" + apiCode[4:]
}

func generatePermName(code string) string {
	parts := strings.Split(code, ":")
	if len(parts) < 2 {
		return code
	}

	nameMap := map[string]string{
		"read":   "读取",
		"write":  "写入",
		"create": "创建",
		"update": "更新",
		"delete": "删除",
		"list":   "列表",
		"detail": "详情",
	}

	var result []string
	for i := 1; i < len(parts); i++ {
		p := parts[i]
		if mapped, ok := nameMap[p]; ok {
			result = append(result, mapped)
		} else {
			result = append(result, p)
		}
	}
	return strings.Join(result, "-")
}
