package prediction

import (
	"encoding/json"
	"fmt"
)

type NodeField struct {
	Node  string `json:"node"`
	Field string `json:"field"`
}

type InputBinding map[string]*NodeField

func ParseBinding(raw string) (InputBinding, error) {
	if raw == "" {
		return InputBinding{}, nil
	}
	var b InputBinding
	if err := json.Unmarshal([]byte(raw), &b); err != nil {
		return nil, err
	}
	return b, nil
}

func (b InputBinding) Validate(workflow map[string]any, required []string) error {
	for _, name := range required {
		f, ok := b[name]
		if !ok || f == nil || f.Node == "" || f.Field == "" {
			return fmt.Errorf("required binding missing: %s", name)
		}
	}
	for name, f := range b {
		if f == nil || f.Node == "" || f.Field == "" {
			continue
		}
		if err := validateNodeField(workflow, f.Node, f.Field); err != nil {
			return fmt.Errorf("binding %s: %w", name, err)
		}
	}
	return nil
}

func validateNodeField(workflow map[string]any, nodeID, field string) error {
	node, ok := workflow[nodeID].(map[string]any)
	if !ok {
		return fmt.Errorf("node %s not found", nodeID)
	}
	inputs, ok := node["inputs"].(map[string]any)
	if !ok {
		return fmt.Errorf("node %s has no inputs", nodeID)
	}
	if _, ok := inputs[field]; !ok {
		return fmt.Errorf("field %s not found on node %s", field, nodeID)
	}
	return nil
}
