package filter

import (
	"strings"

	"github.com/childe/gohangout/field_setter"
	"github.com/childe/gohangout/topology"
	"github.com/childe/gohangout/value_render"
)

// KVConfig defines the configuration structure for KV filter
type KVConfig struct {
	Src         string   `json:"src"`
	Target      string   `json:"target"`
	FieldSplit  string   `json:"field_split"`
	ValueSplit  string   `json:"value_split"`
	Trim        string   `json:"trim"`
	TrimKey     string   `json:"trim_key"`
	IncludeKeys []string `json:"include_keys"`
	ExcludeKeys []string `json:"exclude_keys"`
}

type KVFilter struct {
	config       map[any]any
	fields       map[field_setter.FieldSetter]value_render.ValueRender
	src          value_render.ValueRender
	target       string
	field_split  string
	value_split  string
	trim         string
	trim_key     string
	include_keys map[string]bool
	exclude_keys map[string]bool
}

func init() {
	Register("KV", newKVFilter)
}

func newKVFilter(config map[any]any) topology.Filter {
	// Parse configuration using SafeDecodeConfig helper
	var kvConfig KVConfig

	SafeDecodeConfig("KV", config, &kvConfig)

	// Validate required fields
	ValidateRequiredFields("KV", map[string]any{
		"src":         kvConfig.Src,
		"field_split": kvConfig.FieldSplit,
		"value_split": kvConfig.ValueSplit,
	})

	plugin := &KVFilter{
		config:      config,
		fields:      make(map[field_setter.FieldSetter]value_render.ValueRender),
		target:      kvConfig.Target,
		field_split: kvConfig.FieldSplit,
		value_split: kvConfig.ValueSplit,
		trim:        kvConfig.Trim,
		trim_key:    kvConfig.TrimKey,
	}
	
	plugin.src = value_render.GetValueRender2(kvConfig.Src)

	// Convert include_keys slice to map
	plugin.include_keys = make(map[string]bool)
	for _, key := range kvConfig.IncludeKeys {
		plugin.include_keys[key] = true
	}

	// Convert exclude_keys slice to map
	plugin.exclude_keys = make(map[string]bool)
	for _, key := range kvConfig.ExcludeKeys {
		plugin.exclude_keys[key] = true
	}

	return plugin
}

func (p *KVFilter) Filter(event map[string]any) (map[string]any, bool) {
	msg, err := p.src.Render(event)
	if err != nil || msg == nil {
		return event, false
	}
	A := strings.Split(msg.(string), p.field_split)

	var o map[string]any = event
	if p.target != "" {
		o = make(map[string]any)
		event[p.target] = o
	}

	var success bool = true
	var key string
	for _, kv := range A {
		a := strings.SplitN(kv, p.value_split, 2)
		if len(a) != 2 {
			success = false
			continue
		}

		key = strings.Trim(a[0], p.trim_key)

		if _, ok := p.exclude_keys[key]; ok {
			continue
		}

		if _, ok := p.include_keys[key]; len(p.include_keys) == 0 || ok {
			o[key] = strings.Trim(a[1], p.trim)
		}
	}
	return event, success
}
