package builtin

// convert_test.go birim dönüştürme araçlarını sınar.
//
// En kritik kısım SICAKLIK: kaydırmalı (affine) dönüşümdür. Basit çarpma katsayısı
// ile yapılırsa 0 °C → 0 °F çıkar ve kullanıcıya sessizce YANLIŞ değer verilir.

import (
	"context"
	"math"
	"strings"
	"testing"

	"fiko-ai/internal/tool"
)

func TestUnitConvert(t *testing.T) {
	_, ex := testReg(t, Options{})

	cases := []struct {
		value    float64
		from, to string
		want     float64
	}{
		// Uzunluk
		{25.4, "mm", "in", 1}, // klasik: 25.4 mm = 1 inç
		{1, "m", "mm", 1000},
		{1, "km", "m", 1000},
		{1, "ft", "in", 12},
		{1, "yd", "ft", 3},
		// Kütle
		{1, "kg", "g", 1000},
		{1, "lb", "kg", 0.45359237},
		// Alan / hacim
		{1, "m2", "cm2", 10000},
		{1, "l", "ml", 1000},
		// Hız
		{100, "kmh", "ms", 27.7777777778},
		// SICAKLIK (kaydırmalı!)
		{0, "C", "F", 32},
		{100, "C", "F", 212},
		{32, "F", "C", 0},
		{98.6, "F", "C", 37},
		{0, "C", "K", 273.15},
		{273.15, "K", "C", 0},
		// Açı
		{180, "deg", "rad", math.Pi},
	}

	for _, c := range cases {
		got, _ := toFloat(run(t, ex, "unit.convert", map[string]any{
			"value": c.value, "from": c.from, "to": c.to,
		})["value"])
		if math.Abs(got-c.want) > 1e-6 {
			t.Errorf("%g %s -> %s = %v, beklenen %v", c.value, c.from, c.to, got, c.want)
		}
	}
}

// TestUnitConvertAliases: kullanıcı Türkçe/alternatif yazım kullanınca hata ALMAMALI.
func TestUnitConvertAliases(t *testing.T) {
	_, ex := testReg(t, Options{})
	for _, a := range [][2]string{{"inç", "mm"}, {"metre", "mm"}, {"°C", "°F"}, {"pound", "kg"}, {"derece", "rad"}} {
		if _, err := ex.Execute(context.Background(), tool.Request{
			Ref: "unit.convert", Input: map[string]any{"value": float64(1), "from": a[0], "to": a[1]}, Actor: "user",
		}); err != nil {
			t.Errorf("takma ad %q -> %q reddedildi: %v", a[0], a[1], err)
		}
	}
}

// TestUnitConvertRejectsMismatch: FARKLI BOYUTLAR reddedilmelidir. mm→kg bir
// sayı üretir ama ANLAMSIZDIR; sessizce sayı vermek kullanıcıyı yanıltır.
func TestUnitConvertRejectsMismatch(t *testing.T) {
	_, ex := testReg(t, Options{})
	for _, tc := range [][3]string{
		{"25", "mm", "kg"},
		{"1", "kg", "C"},
		{"5", "mm", "l"},
		{"1", "bulunmayan", "mm"},
	} {
		if _, err := ex.Execute(context.Background(), tool.Request{
			Ref:   "unit.convert",
			Input: map[string]any{"value": float64(1), "from": tc[1], "to": tc[2]},
			Actor: "user",
		}); err == nil {
			t.Errorf("%s %s -> %s reddedilmeliydi", tc[0], tc[1], tc[2])
		}
	}
}

// TestUnitList: kullanıcı hangi birimi yazabileceğini görebilmeli.
func TestUnitList(t *testing.T) {
	_, ex := testReg(t, Options{})
	got := run(t, ex, "unit.list", nil)
	groups, _ := got["groups"].([]map[string]any)
	if len(groups) < 5 {
		t.Errorf("en az 5 grup beklenir: %v", got)
	}
	// "sicaklik" grubu KAYDIRMALI oldugu icin isaretli olmali.
	var sicaklik string
	for _, g := range groups {
		if g["group"] == "sicaklik" {
			sicaklik, _ = g["units"].(string)
		}
	}
	if !strings.Contains(sicaklik, "Fahrenheit") {
		t.Errorf("sicaklik grubu Fahrenheit içermeli: %q", sicaklik)
	}
}
