package viral

import (
	"encoding/json"
	"strings"
)

func firstJSONString(obj map[string]json.RawMessage, keys ...string) string {
	for _, key := range keys {
		raw, ok := obj[key]
		if !ok {
			continue
		}
		var value string
		if err := json.Unmarshal(raw, &value); err == nil {
			if trimmed := strings.TrimSpace(value); trimmed != "" {
				return trimmed
			}
		}
	}
	return ""
}

func flexibleStringFromItem(raw json.RawMessage) string {
	if len(raw) == 0 {
		return ""
	}
	var value string
	if err := json.Unmarshal(raw, &value); err == nil {
		return strings.TrimSpace(value)
	}
	var obj map[string]json.RawMessage
	if err := json.Unmarshal(raw, &obj); err != nil {
		return ""
	}
	if line := firstJSONString(obj, "title", "name", "label", "pillar", "tag", "text", "summary", "description", "value", "content"); line != "" {
		return line
	}
	parts := []string{}
	for _, key := range []string{"title", "name", "label"} {
		if part := firstJSONString(obj, key); part != "" {
			parts = append(parts, part)
			break
		}
	}
	if detail := firstJSONString(obj, "description", "summary", "detail", "reason"); detail != "" {
		parts = append(parts, detail)
	}
	return strings.TrimSpace(strings.Join(parts, "："))
}

func parseFlexibleStringList(raw json.RawMessage) []string {
	if len(raw) == 0 || string(raw) == "null" {
		return nil
	}
	var items []string
	if err := json.Unmarshal(raw, &items); err == nil {
		return cleanLines(items)
	}
	var single string
	if err := json.Unmarshal(raw, &single); err == nil && strings.TrimSpace(single) != "" {
		return cleanLines([]string{single})
	}
	var arr []json.RawMessage
	if err := json.Unmarshal(raw, &arr); err != nil {
		return nil
	}
	out := make([]string, 0, len(arr))
	for _, item := range arr {
		if line := flexibleStringFromItem(item); line != "" {
			out = append(out, line)
		}
	}
	return cleanLines(out)
}

func parseFlexibleSuggestedTags(raw json.RawMessage) []SuggestedTag {
	if len(raw) == 0 || string(raw) == "null" {
		return nil
	}
	var tags []SuggestedTag
	if err := json.Unmarshal(raw, &tags); err == nil && len(tags) > 0 {
		return cleanSuggestedTags(tags)
	}
	var strs []string
	if err := json.Unmarshal(raw, &strs); err == nil {
		out := make([]SuggestedTag, 0, len(strs))
		for _, item := range strs {
			item = strings.TrimSpace(item)
			if item != "" {
				out = append(out, SuggestedTag{Tag: item})
			}
		}
		return cleanSuggestedTags(out)
	}
	var arr []json.RawMessage
	if err := json.Unmarshal(raw, &arr); err != nil {
		return nil
	}
	out := make([]SuggestedTag, 0, len(arr))
	for _, item := range arr {
		if tag := decodeSuggestedTagItem(item); tag.Tag != "" {
			out = append(out, tag)
		}
	}
	return cleanSuggestedTags(out)
}

func decodeSuggestedTagItem(raw json.RawMessage) SuggestedTag {
	var tag SuggestedTag
	if err := json.Unmarshal(raw, &tag); err == nil && strings.TrimSpace(tag.Tag) != "" {
		return tag
	}
	var snake struct {
		Tag          string `json:"tag"`
		Reason       string `json:"reason"`
		SearchIntent string `json:"search_intent"`
		SearchType   string `json:"search_type"`
	}
	if err := json.Unmarshal(raw, &snake); err == nil && strings.TrimSpace(snake.Tag) != "" {
		return SuggestedTag{
			Tag:          strings.TrimSpace(snake.Tag),
			Reason:       strings.TrimSpace(snake.Reason),
			SearchIntent: strings.TrimSpace(snake.SearchIntent),
			SearchType:   strings.TrimSpace(snake.SearchType),
		}
	}
	if line := flexibleStringFromItem(raw); line != "" {
		return SuggestedTag{Tag: line}
	}
	return SuggestedTag{}
}

func pickRawMessage(root map[string]json.RawMessage, keys ...string) json.RawMessage {
	for _, key := range keys {
		if raw, ok := root[key]; ok && len(raw) > 0 && string(raw) != "null" {
			return raw
		}
	}
	return nil
}
