package services

import (
	"testing"
	"time"
)

func TestInstanceAccessServiceValidatesTokenAcrossServiceInstances(t *testing.T) {
	t.Setenv("INSTANCE_ACCESS_TOKEN_SECRET", "cluster-shared-secret")

	issuer := NewInstanceAccessService()
	validator := NewInstanceAccessService()

	token, err := issuer.GenerateToken(7, 42, "openclaw", "/api/v1/instances/42/proxy/", 3001, 5*time.Minute)
	if err != nil {
		t.Fatalf("GenerateToken() error = %v", err)
	}

	validated, err := validator.ValidateToken(token.Token)
	if err != nil {
		t.Fatalf("ValidateToken() error = %v", err)
	}

	if validated.InstanceID != 42 {
		t.Fatalf("validated.InstanceID = %d, want 42", validated.InstanceID)
	}
	if validated.UserID != 7 {
		t.Fatalf("validated.UserID = %d, want 7", validated.UserID)
	}
	if validated.InstanceType != "openclaw" {
		t.Fatalf("validated.InstanceType = %q, want openclaw", validated.InstanceType)
	}
}

func TestInstanceAccessServiceRejectsExpiredSignedToken(t *testing.T) {
	t.Setenv("INSTANCE_ACCESS_TOKEN_SECRET", "cluster-shared-secret")

	service := NewInstanceAccessService()
	token, err := service.GenerateToken(7, 42, "openclaw", "/api/v1/instances/42/proxy/", 3001, -time.Second)
	if err != nil {
		t.Fatalf("GenerateToken() error = %v", err)
	}

	if _, err := service.ValidateToken(token.Token); err == nil || err.Error() != "token expired" {
		t.Fatalf("ValidateToken() error = %v, want token expired", err)
	}
}

func TestInstanceAccessServiceFallsBackToLegacyTokens(t *testing.T) {
	t.Setenv("INSTANCE_ACCESS_TOKEN_SECRET", "cluster-shared-secret")

	service := NewInstanceAccessService()
	service.tokens["legacy-token"] = &AccessToken{
		Token:        "legacy-token",
		InstanceID:   11,
		UserID:       3,
		InstanceType: "ubuntu",
		TargetPort:   3001,
		AccessURL:    "/api/v1/instances/11/proxy/",
		ExpiresAt:    time.Now().Add(time.Minute),
		CreatedAt:    time.Now(),
	}

	validated, err := service.ValidateToken("legacy-token")
	if err != nil {
		t.Fatalf("ValidateToken() error = %v", err)
	}

	if validated.InstanceID != 11 {
		t.Fatalf("validated.InstanceID = %d, want 11", validated.InstanceID)
	}
}

func TestInstanceAccessServiceStopTerminatesCleanup(t *testing.T) {
	t.Setenv("INSTANCE_ACCESS_TOKEN_SECRET", "cluster-shared-secret")

	service := NewInstanceAccessService()

	// Stop should not panic and should be idempotent-safe (only called once).
	service.Stop()

	// After Stop, the service should still be usable for token operations
	// (only the background cleanup goroutine is stopped).
	token, err := service.GenerateToken(1, 1, "openclaw", "/proxy", 3001, time.Minute)
	if err != nil {
		t.Fatalf("GenerateToken after Stop() error = %v", err)
	}
	if _, err := service.ValidateToken(token.Token); err != nil {
		t.Fatalf("ValidateToken after Stop() error = %v", err)
	}
}
