package router_test

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/veylant/ia-gateway/internal/config"
	"github.com/veylant/ia-gateway/internal/router"
)

// defaultRBACConfig is a realistic config used across most tests.
var defaultRBACConfig = &config.RBACConfig{
	UserAllowedModels:  []string{"gpt-4o-mini", "gpt-3.5-turbo", "mistral-small"},
	AuditorCanComplete: false,
}

// ─── Admin ───────────────────────────────────────────────────────────────────

func TestHasAccess_Admin_AllModelsAllowed(t *testing.T) {
	for _, model := range []string{"gpt-4o", "claude-3-opus", "mistral-medium", "llama3"} {
		err := router.HasAccess([]string{"admin"}, model, defaultRBACConfig)
		assert.NoError(t, err, "admin should access %q", model)
	}
}

func TestHasAccess_AdminCaseInsensitive(t *testing.T) {
	err := router.HasAccess([]string{"ADMIN"}, "claude-3-opus", defaultRBACConfig)
	require.NoError(t, err)
}

// ─── Manager ─────────────────────────────────────────────────────────────────

func TestHasAccess_Manager_AllModelsAllowed(t *testing.T) {
	for _, model := range []string{"gpt-4o", "claude-3-opus", "mistral-medium"} {
		err := router.HasAccess([]string{"manager"}, model, defaultRBACConfig)
		assert.NoError(t, err, "manager should access %q", model)
	}
}

func TestHasAccess_ManagerCaseInsensitive(t *testing.T) {
	err := router.HasAccess([]string{"Manager"}, "gpt-4o", defaultRBACConfig)
	require.NoError(t, err)
}

// ─── Auditor ─────────────────────────────────────────────────────────────────

func TestHasAccess_Auditor_Blocked_WhenCanCompleteIsFalse(t *testing.T) {
	err := router.HasAccess([]string{"auditor"}, "gpt-4o-mini", defaultRBACConfig)
	require.Error(t, err)
	assert.Contains(t, err.Error(), "auditor")
}

func TestHasAccess_Auditor_Allowed_WhenCanCompleteIsTrue(t *testing.T) {
	cfg := &config.RBACConfig{
		UserAllowedModels:  defaultRBACConfig.UserAllowedModels,
		AuditorCanComplete: true,
	}
	err := router.HasAccess([]string{"auditor"}, "gpt-4o-mini", cfg)
	require.NoError(t, err)
}

func TestHasAccess_AuditorCaseInsensitive(t *testing.T) {
	err := router.HasAccess([]string{"AUDITOR"}, "gpt-4o-mini", defaultRBACConfig)
	require.Error(t, err)
}

// ─── User ─────────────────────────────────────────────────────────────────────

func TestHasAccess_User_AllowedModel_ExactMatch(t *testing.T) {
	err := router.HasAccess([]string{"user"}, "gpt-4o-mini", defaultRBACConfig)
	require.NoError(t, err)
}

func TestHasAccess_User_AllowedModel_PrefixMatch(t *testing.T) {
	// "gpt-4o-mini" prefix matches "gpt-4o-mini-2024-07-18"
	err := router.HasAccess([]string{"user"}, "gpt-4o-mini-2024-07-18", defaultRBACConfig)
	require.NoError(t, err)
}

func TestHasAccess_User_AllowedModel_MistralSmall(t *testing.T) {
	err := router.HasAccess([]string{"user"}, "mistral-small", defaultRBACConfig)
	require.NoError(t, err)
}

func TestHasAccess_User_UnauthorizedModel_Claude(t *testing.T) {
	err := router.HasAccess([]string{"user"}, "claude-3-opus", defaultRBACConfig)
	require.Error(t, err)
	assert.Contains(t, err.Error(), "claude-3-opus")
}

func TestHasAccess_User_UnauthorizedModel_GPT4o(t *testing.T) {
	err := router.HasAccess([]string{"user"}, "gpt-4o", defaultRBACConfig)
	require.Error(t, err)
	assert.Contains(t, err.Error(), "gpt-4o")
}

func TestHasAccess_UserCaseInsensitive(t *testing.T) {
	err := router.HasAccess([]string{"USER"}, "gpt-4o-mini", defaultRBACConfig)
	require.NoError(t, err)
}

// ─── Unknown / empty roles ────────────────────────────────────────────────────

func TestHasAccess_UnknownRole_TreatedAsUser_AllowedModel(t *testing.T) {
	err := router.HasAccess([]string{"viewer"}, "gpt-4o-mini", defaultRBACConfig)
	require.NoError(t, err) // gpt-4o-mini is in UserAllowedModels
}

func TestHasAccess_UnknownRole_TreatedAsUser_BlockedModel(t *testing.T) {
	err := router.HasAccess([]string{"viewer"}, "claude-3-opus", defaultRBACConfig)
	require.Error(t, err)
}

func TestHasAccess_EmptyRoles_TreatedAsUser(t *testing.T) {
	err := router.HasAccess([]string{}, "gpt-4o-mini", defaultRBACConfig)
	require.NoError(t, err)
}

func TestHasAccess_EmptyRoles_BlockedModel(t *testing.T) {
	err := router.HasAccess([]string{}, "claude-3-opus", defaultRBACConfig)
	require.Error(t, err)
}

// ─── Multi-role ───────────────────────────────────────────────────────────────

func TestHasAccess_MultiRole_AdminWins(t *testing.T) {
	// user has both "user" and "admin" — admin takes priority
	err := router.HasAccess([]string{"user", "admin"}, "claude-3-opus", defaultRBACConfig)
	require.NoError(t, err)
}

func TestHasAccess_MultiRole_ManagerWins(t *testing.T) {
	err := router.HasAccess([]string{"auditor", "manager"}, "claude-3-opus", defaultRBACConfig)
	require.NoError(t, err)
}

// ─── Empty allowed models ─────────────────────────────────────────────────────

func TestHasAccess_EmptyAllowedModels_UserAlwaysBlocked(t *testing.T) {
	cfg := &config.RBACConfig{
		UserAllowedModels:  []string{},
		AuditorCanComplete: false,
	}
	err := router.HasAccess([]string{"user"}, "gpt-4o-mini", cfg)
	require.Error(t, err)
}
