package middleware

import (
	"net/http"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/nexuscrm/kernel/pkg/auth"
	"github.com/nexuscrm/shared/pkg/constants"
)

func TestBackendSessionContextProjectsAuthenticatedUser(t *testing.T) {
	gin.SetMode(gin.TestMode)
	c, _ := gin.CreateTestContext(nil)
	roleID := "00E_ROLE"
	roleName := "Role"
	c.Set(constants.ContextKeyUser, auth.UserSession{
		ID:             "005USER",
		Name:           "Ada",
		Email:          "ada@example.com",
		ProfileId:      "00ePROFILE",
		ProfileName:    "Admin",
		RoleId:         &roleID,
		RoleName:       &roleName,
		ConnectedAppId: " app-1 ",
		Scope:          "api.read",
		GrantType:      "authorization_code",
		SessionClass:   "connected_app",
		SystemPermissions: map[string]bool{
			"ApiEnabled": true,
		},
	})

	lookup := backendSessionContextWriter{}.ReadSession(c)
	if !lookup.OK() {
		t.Fatalf("expected valid session lookup, got %#v", lookup)
	}
	if lookup.User.ProfileID != "00ePROFILE" {
		t.Fatalf("ProfileID = %q, want 00ePROFILE", lookup.User.ProfileID)
	}
	if lookup.User.ConnectedAppID != "app-1" {
		t.Fatalf("ConnectedAppID = %q, want app-1", lookup.User.ConnectedAppID)
	}
	if !lookup.User.SystemPermissions["ApiEnabled"] {
		t.Fatalf("expected system permission projection")
	}
}

func TestBackendSessionContextPreservesPermissionLookupState(t *testing.T) {
	gin.SetMode(gin.TestMode)
	c, _ := gin.CreateTestContext(nil)
	sessionContext := backendSessionContextWriter{}

	if lookup := sessionContext.SystemPermissions(c); lookup.Exists || lookup.Valid {
		t.Fatalf("missing permissions should not exist, got %#v", lookup)
	}

	c.Set(constants.ContextKeySystemPermissions, "wrong-shape")
	if lookup := sessionContext.SystemPermissions(c); !lookup.Exists || lookup.Valid {
		t.Fatalf("wrong-shaped permissions should exist but be invalid, got %#v", lookup)
	}

	c.Set(constants.ContextKeySystemPermissions, map[string]bool{"ApiEnabled": true})
	lookup := sessionContext.SystemPermissions(c)
	if !lookup.OK() || !lookup.Permissions["ApiEnabled"] {
		t.Fatalf("expected valid permissions lookup, got %#v", lookup)
	}
}

func TestBackendSessionContextWritePermissionsInstallsRequestContextValues(t *testing.T) {
	gin.SetMode(gin.TestMode)
	c, _ := gin.CreateTestContext(nil)
	req, err := http.NewRequest(http.MethodGet, "/", nil)
	if err != nil {
		t.Fatal(err)
	}
	c.Request = req

	systemPerms := map[string]bool{"ApiEnabled": true}
	customPerms := map[string]bool{"ConvertLeads": true}
	backendSessionContextWriter{}.WritePermissions(c, systemPerms, customPerms)

	if got, ok := c.Request.Context().Value(constants.ContextKeySystemPermissions).(map[string]bool); !ok || !got["ApiEnabled"] {
		t.Fatalf("request context system permissions = %#v, ok=%v; want ApiEnabled", got, ok)
	}
	if got, ok := c.Request.Context().Value(constants.ContextKeyCustomPermissions).(map[string]bool); !ok || !got["ConvertLeads"] {
		t.Fatalf("request context custom permissions = %#v, ok=%v; want ConvertLeads", got, ok)
	}
}

func TestBackendSessionContextWritesConnectedAppID(t *testing.T) {
	gin.SetMode(gin.TestMode)
	c, _ := gin.CreateTestContext(nil)
	req, err := http.NewRequest(http.MethodGet, "/", nil)
	if err != nil {
		t.Fatal(err)
	}
	c.Request = req

	backendSessionContextWriter{}.WriteConnectedAppID(c, " app-1 ")

	value, exists := c.Get(ContextKeyConnectedAppID)
	if !exists || value != "app-1" {
		t.Fatalf("gin connected app id = %#v, exists=%v; want app-1", value, exists)
	}
	if got := ConnectedAppIDFromContext(c.Request.Context()); got != "app-1" {
		t.Fatalf("request context connected app id = %q, want app-1", got)
	}
}
