package agent

// args_test.go: modelin bozuk gönderdiği argümanların düzeltildiğini doğrular.

import (
	"testing"

	"fiko-ai/internal/llm"
)

// ---- args.go ----

func TestNormalizeArgs_ConvertsBySchema(t *testing.T) {
	schema := map[string]any{"type": "object", "properties": map[string]any{
		"amount":   map[string]any{"type": "number"},
		"count":    map[string]any{"type": "integer"},
		"append":   map[string]any{"type": "boolean"},
		"data":     map[string]any{"type": "object"},
		"tags":     map[string]any{"type": "array"},
		"ref":      map[string]any{"type": "string"},
		"bilinmez": map[string]any{"type": "number"}, // şemada yok → dokunulmaz
	}}
	in := map[string]any{
		"amount": "500", "count": "3", "append": "true",
		"data": `{"name":"Aril"}`, "tags": `["a","b"]`,
		"ref": 42, "bilinmez": "metin kalır",
	}
	got := normalizeArgs(schema, in)

	if got["amount"] != float64(500) {
		t.Errorf("amount: %T %v (sayı olmalı)", got["amount"], got["amount"])
	}
	if got["count"] != 3 {
		t.Errorf("count: %T %v (tam sayı olmalı)", got["count"], got["count"])
	}
	if got["append"] != true {
		t.Errorf("append: %T %v (boolean olmalı)", got["append"], got["append"])
	}
	if m, ok := got["data"].(map[string]any); !ok || m["name"] != "Aril" {
		t.Errorf("data nesneye çevrilmeli: %T %v", got["data"], got["data"])
	}
	if arr, ok := got["tags"].([]any); !ok || len(arr) != 2 {
		t.Errorf("tags diziye çevrilmeli: %T %v", got["tags"], got["tags"])
	}
	if got["ref"] != "42" {
		t.Errorf("ref sayıdan metne çevrilmeli: %T %v", got["ref"], got["ref"])
	}
	if got["bilinmez"] != "metin kalır" {
		t.Errorf("şemada olmayan alan DOKUNULMAMALI: %v", got["bilinmez"])
	}
}

// Türkçe yazım: binlik ayracı NOKTA, ondalık ayracı VİRGÜL ("1.234,56").
func TestParseLooseFloat_TurkishAndEnglish(t *testing.T) {
	cases := map[string]float64{
		"500":      500,
		"1.234":    1234, // binlik ayraç
		"1.234,56": 1234.56,
		"1,50":     1.5,     // ondalık
		"1,234.56": 1234.56, // İngilizce yazım
		"12":       12,
	}
	for in, want := range cases {
		got, ok := parseLooseFloat(in)
		if !ok || got != want {
			t.Errorf("parseLooseFloat(%q) = %v,%v; beklenen %v", in, got, ok, want)
		}
	}
	for _, bad := range []string{"", "abc", "notlar/x.txt"} {
		if _, ok := parseLooseFloat(bad); ok {
			t.Errorf("parseLooseFloat(%q) başarısız olmalıydı", bad)
		}
	}
}

// Değişiklik yoksa AYNI harita döner (gereksiz kopya/kayıt olmaz).
//
// Neden harita KİMLİĞİ önemli? ToolRun kaydı ve olay önizlemesi bu haritayı saklar; her
// çağrıda kopya üretmek bellekte kopuk kayıtlar bırakır (aynı çağrının iki kaydı).
func TestNormalizeArgs_NoChangeReturnsSameMap(t *testing.T) {
	schema := map[string]any{"properties": map[string]any{"a": map[string]any{"type": "number"}}}
	in := map[string]any{"a": float64(1)}
	got := normalizeArgs(schema, in)

	got["içerik"] = "aynı harita mı?"
	if _, ok := in["içerik"]; !ok {
		t.Error("değişiklik yokken yeni harita üretilmemeli (aynı harita dönmeli)")
	}
}

// ---- args.go: normalizePath ----

func TestNormalizePath(t *testing.T) {
	cases := map[string]string{
		"/notlar/plan.txt":           "notlar/plan.txt",
		"data/tools/notlar/plan.txt": "notlar/plan.txt",
		"./notlar/plan.txt":          "notlar/plan.txt",
		`\notlar\plan.txt`:           "notlar/plan.txt",
		"notlar/plan.txt":            "notlar/plan.txt",
		"data/tools/":                "",
		"/":                          "",
	}
	for in, want := range cases {
		if got := normalizePath(in); got != want {
			t.Errorf("normalizePath(%q) = %q, beklenen %q", in, got, want)
		}
	}
}

// Dosya aracında mutlak/köklü yol göreli biçime çevrilir (kök dışına çıkma reddi sürsün diye).
func TestNormalizeArgsInPlace_FSToolsTrimRoot(t *testing.T) {
	schema := map[string]any{"properties": map[string]any{"path": map[string]any{"type": "string"}}}
	got := normalizeArgsInPlace("fs.read_text", schema, map[string]any{"path": "/notlar/x.txt"})
	if got["path"] != "notlar/x.txt" {
		t.Errorf("fs.read_text path düzeltilmeli: %v", got["path"])
	}
	// biz.* araçlarında `path` yok; alan adı tesadüfen geçse bile kök öneki KIRPILMAZ.
	keep := normalizeArgsInPlace("biz.add", schema, map[string]any{"path": "/notlar/x.txt"})
	if keep["path"] != "/notlar/x.txt" {
		t.Errorf("biz.* aracında yol değiştirilmemeli: %v", keep["path"])
	}
}

// ---- toolSchemaOf ----

func TestToolSchemaOf(t *testing.T) {
	tools := []llm.ToolSpec{
		{Name: "a", InputSchema: map[string]any{"properties": map[string]any{"x": map[string]any{"type": "number"}}}},
	}
	if toolSchemaOf(tools, "a") == nil {
		t.Error("bulunan araç için şema dönmeli")
	}
	if toolSchemaOf(tools, "yok") != nil {
		t.Error("bulunmayan araç için şema nil olmalı (dönüşüm yapılmaz)")
	}
}
