package services

import (
	"github.com/google/uuid"
	"testing"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"github.com/stretchr/testify/assert"
	"go.uber.org/zap"
)

func TestChatService_GenerateToken(t *testing.T) {
	logger := zap.NewNop()
	jwtSecret := "supersecretchatkey"
	service := NewChatService(jwtSecret, logger)

	userID := uuid.New()
	username := "testuser"

	tokenResponse, err := service.GenerateToken(userID, username)
	assert.NoError(t, err)
	assert.NotNil(t, tokenResponse)
	assert.NotEmpty(t, tokenResponse.Token)
	assert.Greater(t, tokenResponse.ExpiresIn, int64(0))
	assert.Equal(t, "/ws", tokenResponse.WSUrl)

	// Verify token content
	parsedToken, err := jwt.Parse(tokenResponse.Token, func(token *jwt.Token) (interface{}, error) {
		assert.Equal(t, jwt.SigningMethodHS256, token.Method)
		return []byte(jwtSecret), nil
	})
	assert.NoError(t, err)
	assert.True(t, parsedToken.Valid)

	claims, ok := parsedToken.Claims.(jwt.MapClaims)
	assert.True(t, ok)
	assert.Equal(t, userID.String(), claims["sub"]) // Expect string UUID
	assert.Equal(t, username, claims["name"])
	assert.Equal(t, "veza-chat", claims["aud"])
	assert.Equal(t, "veza-backend", claims["iss"])

	// Check expiration (should be close to 15 minutes)
	exp := time.Unix(int64(claims["exp"].(float64)), 0)
	assert.InDelta(t, time.Now().Add(15*time.Minute).Unix(), exp.Unix(), float64(time.Second*5))
}

func TestChatService_GenerateToken_EmptyUsername(t *testing.T) {
	logger := zap.NewNop()
	jwtSecret := "supersecretchatkey"
	service := NewChatService(jwtSecret, logger)

	userID := uuid.New()
	username := "" // Empty username

	tokenResponse, err := service.GenerateToken(userID, username)
	assert.NoError(t, err)
	assert.NotNil(t, tokenResponse)
	assert.NotEmpty(t, tokenResponse.Token)

	parsedToken, err := jwt.Parse(tokenResponse.Token, func(token *jwt.Token) (interface{}, error) {
		return []byte(jwtSecret), nil
	})
	assert.NoError(t, err)
	claims, _ := parsedToken.Claims.(jwt.MapClaims)
	assert.Equal(t, username, claims["name"]) // Should still be empty
}

func TestChatService_GenerateToken_InvalidSecret(t *testing.T) {
	logger := zap.NewNop()
	jwtSecret := "" // Invalid secret
	service := NewChatService(jwtSecret, logger)

	userID := uuid.New()
	username := "testuser"

	_, err := service.GenerateToken(userID, username)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "JWT secret is not configured")
}
