package encoders

import (
	"fmt"
	"strings"

	parserUtils "git.max-richter.dev/max/marka/parser/utils"
	"git.max-richter.dev/max/marka/renderer/utils"
	"git.max-richter.dev/max/marka/template"

	"go.yaml.in/yaml/v4"
)

func flattenInto(in map[string]any) map[string]any {
	out := make(map[string]any)

	var recur func(prefix string, m map[string]any)
	recur = func(prefix string, m map[string]any) {
		for k, v := range m {
			key := k
			if prefix != "" {
				key = prefix + "." + k
			}

			switch vv := v.(type) {
			case map[string]any:
				if len(vv) == 1 {
					recur(key, vv)
				} else {
					out[key] = vv
				}
			case map[any]any:
				tmp := make(map[string]any, len(vv))
				for kk, vv2 := range vv {
					if ks, ok := kk.(string); ok {
						tmp[ks] = vv2
					}
				}
				if len(tmp) == 1 {
					recur(key, tmp)
				} else {
					out[key] = tmp
				}
			default:
				out[key] = v
			}
		}
	}

	recur("", in)
	return out
}

func RenderYaml(data map[string]any, block template.Block) (string, error) {
	renderedMap := make(map[string]any)
	for _, field := range block.Fields {
		if field.Hidden {
			continue
		}

		var fieldValue any
		var found bool

		if field.CodecType == template.CodecConst {
			fieldValue = field.Value
			found = true
		} else {
			fieldValue, found = utils.GetValueFromPath(data, field.Path)
		}

		if found {
			renderedMap = parserUtils.SetPathValue(field.Path, fieldValue, renderedMap).(map[string]any)
		}
	}

	renderedMap = flattenInto(renderedMap)

	b, err := yaml.Marshal(renderedMap)
	if err != nil {
		return "", fmt.Errorf("failed to marshal YAML for path '%s': %w", block.Path, err)
	}
	return strings.TrimSuffix(string(b), "\n"), nil
}
