package topdata

import (
	"fmt"
	"strings"
)

func isNullLike(value any) bool {
	if value == nil {
		return true
	}
	text, ok := value.(string)
	if !ok {
		return false
	}
	return strings.TrimSpace(text) == nullValue
}

func normalizeWikiMetadataKey(key string) string {
	switch normalizeMetadataKey(key) {
	case "reqfeats", "req_feats":
		return "reqfeats"
	case "generate", "wikigenerate":
		return "generate"
	case "canonical", "wikicanonical":
		return "canonical"
	case "status", "wikistatus":
		return "status"
	default:
		return ""
	}
}

func legacyWikiMetadataField(key string) string {
	switch normalizeMetadataKey(key) {
	case "wikireqfeats":
		return "reqfeats"
	case "wikigenerate":
		return "generate"
	case "wikicanonical":
		return "canonical"
	case "wikistatus":
		return "status"
	default:
		return ""
	}
}

func parseWikiMetadata(raw any) (map[string]any, error) {
	obj, ok := raw.(map[string]any)
	if !ok {
		return nil, fmt.Errorf("must be an object")
	}
	wiki := map[string]any{}
	for key, value := range obj {
		normalized := normalizeWikiMetadataKey(key)
		if normalized == "" {
			return nil, fmt.Errorf("unknown field %q", key)
		}
		if isNullLike(value) {
			continue
		}
		wiki[normalized] = cloneAuthoringValue(value)
	}
	return wiki, nil
}

func mergeMetadataMaps(base, overlay map[string]any) map[string]any {
	if len(base) == 0 && len(overlay) == 0 {
		return nil
	}
	out := map[string]any{}
	for key, value := range base {
		out[key] = cloneAuthoringValue(value)
	}
	for key, value := range overlay {
		baseValue, hasBase := out[key]
		baseMap, baseIsMap := baseValue.(map[string]any)
		valueMap, valueIsMap := value.(map[string]any)
		if hasBase && baseIsMap && valueIsMap {
			out[key] = mergeMetadataMaps(baseMap, valueMap)
			continue
		}
		out[key] = cloneAuthoringValue(value)
	}
	if len(out) == 0 {
		return nil
	}
	return out
}

func parseExistingMetadata(row map[string]any) (map[string]any, error) {
	rawMeta, ok := lookupField(row, "meta")
	if !ok {
		return nil, nil
	}
	return parseRowMetadata(rawMeta)
}

func setLegacyWikiMetadata(row map[string]any, field string, value any) error {
	wikiKey := legacyWikiMetadataField(field)
	if wikiKey == "" {
		return nil
	}

	meta, err := parseExistingMetadata(row)
	if err != nil {
		return err
	}
	if meta == nil {
		meta = map[string]any{}
	}

	wiki, _ := meta["wiki"].(map[string]any)
	if wiki == nil {
		wiki = map[string]any{}
	}

	if isNullLike(value) {
		delete(wiki, wikiKey)
	} else {
		wiki[wikiKey] = cloneAuthoringValue(value)
	}

	if len(wiki) == 0 {
		delete(meta, "wiki")
	} else {
		meta["wiki"] = wiki
	}
	if len(meta) == 0 {
		delete(row, "meta")
	} else {
		row["meta"] = meta
	}
	return nil
}

func canonicalizeWikiMetadataDocument(obj map[string]any) {
	if rawColumns, ok := obj["columns"].([]any); ok {
		filtered := make([]any, 0, len(rawColumns))
		for _, raw := range rawColumns {
			column, ok := raw.(string)
			if ok && isAuthoringOnlyField(column) {
				continue
			}
			filtered = append(filtered, raw)
		}
		obj["columns"] = filtered
	}
	if rows, ok := obj["rows"].([]any); ok {
		for _, raw := range rows {
			row, ok := raw.(map[string]any)
			if !ok {
				continue
			}
			canonicalizeWikiMetadataRow(row)
		}
	}
	if entries, ok := obj["entries"].(map[string]any); ok {
		for _, raw := range entries {
			row, ok := raw.(map[string]any)
			if !ok {
				continue
			}
			canonicalizeWikiMetadataRow(row)
		}
	}
	if overrides, ok := obj["overrides"].([]any); ok {
		for _, raw := range overrides {
			row, ok := raw.(map[string]any)
			if !ok {
				continue
			}
			canonicalizeWikiMetadataRow(row)
		}
	}
}

func canonicalizeWikiMetadataRow(row map[string]any) {
	for _, field := range []string{"WIKIREQFEATS", "WIKIGENERATE", "WIKICANONICAL", "WIKISTATUS"} {
		value, ok := row[field]
		if !ok {
			continue
		}
		_ = setLegacyWikiMetadata(row, field, value)
		delete(row, field)
	}
}
