package tool

import (
	"errors"
	"fmt"
	"strings"
)

// Servis hataları. API katmanı bunları HTTP durumlarına eşler (bkz. api/errors.go).
var (
	// ErrNotFound istenen tool yoksa döner.
	ErrNotFound = errors.New("tool: bulunamadı")
	// ErrDuplicateName aynı ada sahip başka bir tool varsa döner (ad benzersizdir).
	ErrDuplicateName = errors.New("tool: bu ada sahip bir tool zaten var")
	// ErrDisabled tool kapatılmışsa döner.
	ErrDisabled = errors.New("tool: devre dışı bırakılmış")
	// ErrNotExecutable tool'un çalışma zamanı uygulaması yoksa döner.
	// Bu fazda yalnızca "builtin" tool'lar yürütülebilir; tanımı olan custom tool'lar yalnızca listelenir.
	ErrNotExecutable = errors.New("tool: çalıştırılabilir uygulaması yok")
	// ErrBuiltin tool kodla geldiği için silinemez (yalnızca kapatılabilir).
	ErrBuiltin = errors.New("tool: yerleşik tool silinemez, kapatılabilir")
)

// FieldError tek bir alanın doğrulama hatasıdır (skill.FieldError ile aynı sözleşme:
// arayüz alanı işaretleyebilsin diye yapısaldır).
type FieldError struct {
	Field   string `json:"field"`
	Message string `json:"message"`
}

func (e FieldError) Error() string { return e.Field + ": " + e.Message }

// ValidationError bir ya da daha fazla alan hatasını taşır (tanım geçersiz).
type ValidationError struct{ Errors []FieldError }

func (e *ValidationError) Error() string {
	parts := make([]string, len(e.Errors))
	for i, fe := range e.Errors {
		parts[i] = fe.Error()
	}
	return "tool geçersiz — " + strings.Join(parts, "; ")
}

// InputError girdi doğrulaması hatasıdır: tool geçerli, GİRDİ geçersiz.
// Tanım hatasından (ValidationError) ayrı tutulur: kullanıcı iki farklı hatayı
// farklı yerlerde düzeltmelidir (bir tanımda, bir çağrıda).
type InputError struct {
	Tool   string
	Errors []FieldError
}

func (e *InputError) Error() string {
	return fmt.Sprintf("tool %q girdisi geçersiz: %d hata", e.Tool, len(e.Errors))
}

// Field hataları alan adıyla birlikte döndürür; kök hata alan adı olmadan gelir.
func (e *InputError) Fields() []FieldError { return e.Errors }

// FailedError tool'un kendi hatasıdır (ağ, dosya, süreç...). Uygulama katmanı
// Retryable() bildiriyorsa Executor tekrar dener.
type FailedError struct {
	Tool   string
	Reason string
	err    error
}

func (e *FailedError) Error() string {
	if e.Reason != "" {
		return fmt.Sprintf("tool %q başarısız: %s", e.Tool, e.Reason)
	}
	return fmt.Sprintf("tool %q başarısız: %v", e.Tool, e.err)
}

func (e *FailedError) Unwrap() error { return e.err }

// Retryable varsayılan olarak YANLIŞTIR: geçici olmayan bir hata (ör. "dosya yok")
// 4 kez denendiğinde yalnızca zarar verir. Uygulama geçici olduğunu bildirirse
// Failed{Retryable: true} ile dönmelidir.
func (e *FailedError) Retryable() bool {
	var r interface{ Retryable() bool }
	if errors.As(e.err, &r) {
		return r.Retryable()
	}
	return false
}

// RetryableError geçici hatayı bildirmek için uygulama katmanının döndürdüğü hata arayüzüdür.
type RetryableError interface {
	error
	Retryable() bool
}

// Temporary geçici hata sarmalayıcısı: uygulama "ağ koptu, birazdan dene" diyebilir.
func Temporary(err error) RetryableError { return temporary{err} }

type temporary struct{ err error }

func (t temporary) Error() string   { return t.err.Error() }
func (t temporary) Unwrap() error   { return t.err }
func (t temporary) Retryable() bool { return true }
