package persona

import (
	"context"
	"errors"
	"log/slog"
	"strings"
	"time"
)

// Service, profil iş kurallarını uygular ve ajan için "bu kullanıcıya hangi
// davranış kuralları uygulanır?" sorusunu çözer.
type Service struct {
	repo Repository
	now  func() time.Time
	log  *slog.Logger
}

// NewService, profil servisini üretir (depo zorunludur).
func NewService(repo Repository, log *slog.Logger) (*Service, error) {
	if repo == nil {
		return nil, errors.New("persona: depo zorunludur")
	}
	return &Service{repo: repo, now: time.Now, log: log}, nil
}

// nowFn testin saat kaydırma yapabilmesi içindir (notify paketi deseni).
func (s *Service) nowFn(f func() time.Time) { s.now = f }

// List tüm profilleri döner (yönetici ekranı).
func (s *Service) List(ctx context.Context) ([]Profile, error) {
	if s.repo == nil {
		return nil, errors.New("persona: depo yapılandırılmamış")
	}
	return s.repo.List(ctx)
}

// Create yeni profil kaydeder (doğrulama New içinde yapılır).
func (s *Service) Create(ctx context.Context, in NewInput) (Profile, error) {
	if s.repo == nil {
		return Profile{}, errors.New("persona: depo yapılandırılmamış")
	}
	if in.Now.IsZero() {
		in.Now = s.now()
	}
	p, err := New(in)
	if err != nil {
		return Profile{}, err
	}
	return s.repo.Create(ctx, p)
}

// Update mevcut profili günceller.
func (s *Service) Update(ctx context.Context, id string, in UpdateInput) (Profile, error) {
	if s.repo == nil {
		return Profile{}, errors.New("persona: depo yapılandırılmamış")
	}
	cur, err := s.repo.Get(ctx, id)
	if err != nil {
		return Profile{}, err
	}
	if in.Now.IsZero() {
		in.Now = s.now()
	}
	if err := cur.Apply(in); err != nil {
		return Profile{}, err
	}
	return s.repo.Update(ctx, cur)
}

// Delete profili siler.
func (s *Service) Delete(ctx context.Context, id string) error {
	if s.repo == nil {
		return errors.New("persona: depo yapılandırılmamış")
	}
	return s.repo.Delete(ctx, id)
}

// Active, bir kullanıcıya atanmış profilleri istem için çözer.
//
// Neden hata YUTULUR? Profil, davranış zenginliğidir: depo/ayar hatası sohbeti
// ÇÖKERTMEMELİ, kullanıcı yalnızca profil kuralları olmadan konuşur. Bu yüzden
// hata loglanır, isteme sessizce eklenmez. (Bellek getirme de aynı sebepten
// "hata olursa tur değişmez" politikasındadır.)
func (s *Service) Active(ctx context.Context, userID string) []Profile {
	// Nil ALICI da korunur: NewService hata döndüğünde çağıran yine de elde
	// ettiği (nil) servisi saklayıp çağırabilir — sohbet çökmemeli.
	if s == nil || s.repo == nil || strings.TrimSpace(userID) == "" {
		return nil
	}
	list, err := s.repo.GetByUser(ctx, userID)
	if err != nil {
		if s.log != nil {
			s.log.Warn("kullanıcı profili okunamadı (sohbet profil kuralları olmadan devam ediyor)",
				"kullanıcı", userID, "err", err)
		}
		return nil
	}
	return list
}

// ByUser, yönetici ekranı için kullanıcının profillerini döner (hata ile).
func (s *Service) ByUser(ctx context.Context, userID string) ([]Profile, error) {
	if s.repo == nil {
		return nil, errors.New("persona: depo yapılandırılmamış")
	}
	return s.repo.GetByUser(ctx, userID)
}
