// Package workflow Agent Builder'ın (Faz 9) çekirdeğidir: kullanıcının kod yazmadan çizdiği
// node tabanlı iş akışları (Input → Memory → RAG → LLM → Tool → Output ...), bunların
// yürütülmesi ve her yürütmenin adım adım kaydı (execution tracking).
//
// Tasarım kararları:
//   - Akış JSON olarak saklanır (Nodes + Edges); arayüz aynı biçimi çizer ve düzenler.
//   - Paket agent/skill/tool/knowledge paketlerini BİLMEZ; ihtiyacı olan yetenekleri küçük arayüzlerle
//     ister (Deps). Gerçek uygulamalar cmd/server'da takılır (agent paketiyle aynı desen).
//   - Her (node, dal) çiftinin tek çıkış kenarı vardır: yürütme doğrusal + dallanmalıdır, paralel değil.
//     Bu, akışı açıklanabilir ve zaman çizelgesini sıralı yapar.
//   - Kaydetme esnektir (taslak kaydedilebilir); ÇALIŞTIRMA katıdır (Check geçmeden çalışmaz).
package workflow

import (
	"strings"
	"time"
	"unicode/utf8"
)

// NodeType bir node'un türüdür (PROJE.MD: Input, LLM, Memory, RAG, Skill, Tool, Condition, Loop, Transform, Output).
type NodeType string

const (
	NodeInput     NodeType = "input"
	NodeLLM       NodeType = "llm"
	NodeMemory    NodeType = "memory"
	NodeRAG       NodeType = "rag"
	NodeSkill     NodeType = "skill"
	NodeTool      NodeType = "tool"
	NodeCondition NodeType = "condition"
	NodeLoop      NodeType = "loop"
	NodeTransform NodeType = "transform"
	NodeOutput    NodeType = "output"
)

// AllNodeTypes arayüzün paleti ve doğrulama için sıralı liste.
var AllNodeTypes = []NodeType{
	NodeInput, NodeMemory, NodeRAG, NodeSkill, NodeLLM, NodeTool,
	NodeCondition, NodeLoop, NodeTransform, NodeOutput,
}

// Valid bilinen bir node türü mü?
func (t NodeType) Valid() bool {
	for _, v := range AllNodeTypes {
		if t == v {
			return true
		}
	}
	return false
}

// Kenar dalları. Condition yalnızca true/false, Loop yalnızca body (ve "" = döngü bitince), diğerleri "".
const (
	BranchNext  = ""
	BranchTrue  = "true"
	BranchFalse = "false"
	BranchBody  = "body"
)

// Sınırlar: kötü niyetli/yanlış girdinin kayıt şişirmesini ve sonsuz yürütmeyi önler.
const (
	MaxNameRunes   = 100
	MaxDescRunes   = 500
	MaxLabelRunes  = 100
	MaxNodes       = 100
	MaxEdges       = 300
	MaxIDLen       = 40
	MaxConfigBytes = 16 << 10 // node başına config JSON üst sınırı

	// MaxSteps bir yürütmedeki toplam node çalıştırma sayısıdır (döngü gövdeleri dahil).
	MaxSteps = 200
	// MaxLoopIterations tek bir Loop node'unun en çok tekrarıdır.
	MaxLoopIterations = 50
)

// Position node'un tuval üzerindeki yeri (yalnızca arayüz için; yürütmeyi etkilemez).
type Position struct {
	X float64 `bson:"x" json:"x"`
	Y float64 `bson:"y" json:"y"`
}

// Node akıştaki tek bir adımdır. Config alanları türe göre değişir (bkz. engine.go node açıklamaları).
type Node struct {
	ID       string         `bson:"id" json:"id"`
	Type     NodeType       `bson:"type" json:"type"`
	Label    string         `bson:"label,omitempty" json:"label,omitempty"`
	Config   map[string]any `bson:"config,omitempty" json:"config,omitempty"`
	Position Position       `bson:"position" json:"position"`
}

// Edge iki node'u bağlar. Branch hangi çıkıştan çıkıldığını söyler (BranchNext/True/False/Body).
type Edge struct {
	ID     string `bson:"id" json:"id"`
	From   string `bson:"from" json:"from"`
	To     string `bson:"to" json:"to"`
	Branch string `bson:"branch,omitempty" json:"branch,omitempty"`
}

// Workflow kullanıcının kayıtlı akışıdır (PROJE.MD: "Workflow MongoDB'ye JSON olarak kaydedilsin").
type Workflow struct {
	ID          string    `bson:"_id" json:"id"`
	UserID      string    `bson:"userId" json:"userId"`
	Name        string    `bson:"name" json:"name"`
	Description string    `bson:"description,omitempty" json:"description,omitempty"`
	Nodes       []Node    `bson:"nodes" json:"nodes"`
	Edges       []Edge    `bson:"edges" json:"edges"`
	CreatedAt   time.Time `bson:"createdAt" json:"createdAt"`
	UpdatedAt   time.Time `bson:"updatedAt" json:"updatedAt"`
}

// Clone derin kopya döndürür (Config haritaları dahil); depolar ve çağıranlar birbirinin verisini bozmasın.
func (w Workflow) Clone() Workflow {
	c := w
	c.Nodes = make([]Node, len(w.Nodes))
	for i, n := range w.Nodes {
		n.Config = cloneMap(n.Config)
		c.Nodes[i] = n
	}
	c.Edges = append([]Edge{}, w.Edges...)
	return c
}

// FieldError tek alanın doğrulama hatasıdır (skill/tool/knowledge ile aynı JSON sözleşmesi).
type FieldError struct {
	Field   string `json:"field"`
	Message string `json:"message"`
}

// ValidationError bir ya da daha çok alan hatasını taşır.
type ValidationError struct {
	Errors []FieldError
	// NotRunnable true ise akış KAYDEDİLEBİLİR ama ÇALIŞTIRILAMAZ (Check hatası).
	NotRunnable bool
}

func (e *ValidationError) Error() string {
	if len(e.Errors) == 0 {
		return "workflow: doğrulama hatası"
	}
	parts := make([]string, 0, len(e.Errors))
	for _, fe := range e.Errors {
		parts = append(parts, fe.Field+": "+fe.Message)
	}
	return "workflow: geçersiz: " + strings.Join(parts, "; ")
}

// cloneMap/cloneAny JSON benzeri değerlerin derin kopyasıdır.
func cloneMap(m map[string]any) map[string]any {
	if m == nil {
		return nil
	}
	out := make(map[string]any, len(m))
	for k, v := range m {
		out[k] = cloneAny(v)
	}
	return out
}

func cloneAny(v any) any {
	switch x := v.(type) {
	case map[string]any:
		return cloneMap(x)
	case []any:
		out := make([]any, len(x))
		for i := range x {
			out[i] = cloneAny(x[i])
		}
		return out
	default:
		return v
	}
}

func runes(s string) int { return utf8.RuneCountInString(s) }
