package dialogue

import (
	"testing"
	"time"
)

func TestSessionExpiry(t *testing.T) {
	now := time.Date(2026, 7, 6, 12, 0, 0, 0, time.UTC)
	sess := &Session{
		Intent:    IntentQuery,
		Timestamp: now,
		TTL:       2 * time.Minute,
	}
	if sess.IsExpired(now) {
		t.Error("session should not be expired at creation time")
	}
	if sess.IsExpired(now.Add(1 * time.Minute)) {
		t.Error("session should not be expired after 1 minute")
	}
	if !sess.IsExpired(now.Add(3 * time.Minute)) {
		t.Error("session should be expired after 3 minutes")
	}
}

func TestSessionStorePutGet(t *testing.T) {
	now := time.Date(2026, 7, 6, 12, 0, 0, 0, time.UTC)
	store := NewSessionStore(2 * time.Minute)

	if s := store.Get("nonexistent", now); s != nil {
		t.Error("expected nil for non-existent session")
	}

	sess := &Session{Intent: IntentQuery, Timestamp: now}
	store.Put("user1", sess)
	got := store.Get("user1", now)
	if got == nil {
		t.Fatal("expected session after Put")
	}
	if got.Intent != IntentQuery {
		t.Errorf("intent = %q, want query", got.Intent)
	}

	later := now.Add(5 * time.Minute)
	if s := store.Get("user1", later); s != nil {
		t.Error("expected nil for expired session")
	}
}

func TestSessionStoreDefaultTTL(t *testing.T) {
	store := NewSessionStore(0)
	if store.defaultTTL != 2*time.Minute {
		t.Errorf("defaultTTL = %v, want 2m", store.defaultTTL)
	}
}

func TestSessionStoreCustomTTL(t *testing.T) {
	// A session with an explicit TTL should use that instead of the default.
	now := time.Date(2026, 7, 6, 12, 0, 0, 0, time.UTC)
	store := NewSessionStore(2 * time.Minute)

	sess := &Session{Intent: IntentQuery, Timestamp: now, TTL: 15 * time.Minute}
	store.Put("chatty", sess)

	// Should still be alive at 10 minutes (past the 2m default).
	if s := store.Get("chatty", now.Add(10*time.Minute)); s == nil {
		t.Error("chat session with 15m TTL expired at 10m — custom TTL not applied")
	}
	// Should be expired after 20 minutes.
	if s := store.Get("chatty", now.Add(20*time.Minute)); s != nil {
		t.Error("chat session with 15m TTL should be expired at 20m")
	}
}

func TestInheritSlots(t *testing.T) {
	now := time.Date(2026, 7, 6, 0, 0, 0, 0, time.UTC)

	prev := Slots{Text: "Moscow", HasKey: true, Key: "location"}
	cur := Slots{}
	inherited := InheritSlots(prev, cur)
	if !inherited.HasKey || inherited.Key != "location" {
		t.Error("should inherit key from previous")
	}

	cur2 := Slots{HasKey: true, Key: "London"}
	inherited2 := InheritSlots(prev, cur2)
	if inherited2.Key != "London" {
		t.Error("should keep current key when present")
	}

	prevTime := Slots{HasTime: true, Time: now}
	inherited3 := InheritSlots(prevTime, Slots{})
	if !inherited3.HasTime || !inherited3.Time.Equal(now) {
		t.Error("should inherit time")
	}

	prevFn := Slots{HasFn: true, Fn: "status", Args: []string{"nginx"}}
	inherited4 := InheritSlots(prevFn, Slots{})
	if !inherited4.HasFn || inherited4.Fn != "status" {
		t.Error("should inherit fn")
	}
	if len(inherited4.Args) != 1 || inherited4.Args[0] != "nginx" {
		t.Error("should inherit args")
	}

	inherited5 := InheritSlots(prevFn, Slots{HasFn: true, Fn: "restart", Args: []string{"docker"}})
	if len(inherited5.Args) != 1 || inherited5.Args[0] != "docker" {
		t.Error("should keep current args")
	}

	prevText := Slots{Text: "какая погода в москве"}
	inherited6 := InheritSlots(prevText, Slots{Text: ""})
	if inherited6.Text != "какая погода в москве" {
		t.Error("should inherit text when current is empty")
	}

	prevValue := Slots{Key: "water", HasKey: true, Value: `"drank"`}
	inherited7 := InheritSlots(prevValue, Slots{})
	if inherited7.Value != `"drank"` {
		t.Error("should inherit value when current is empty")
	}
	kept := InheritSlots(prevValue, Slots{Value: "2l"})
	if kept.Value != "2l" {
		t.Error("should keep current value")
	}
}
