package scenarios_test

// Security scenario tests for Session Lifecycle.
//
// These verify that session revocation works correctly for all
// credential change events, and that deleted/locked users cannot
// continue using existing tokens.

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"testing"
	"time"

	"github.com/nexuscrm/tests/contract/internal/liveapi"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// ---------- SEC-004: Deleted user session is revoked immediately ----------

func TestSEC004_DeletedUserSessionRevoked(t *testing.T) {
	// Scenario: Create a test user, login to get a token, admin deletes
	// the user, then verify the token is rejected on next API call.
	//
	// Without fix: DeleteUser (auth_user_mgmt.go:195-211) does not call
	// RevokeAllSessionsForUser, so the JWT remains valid until expiry.
	//
	// Evidence: DeleteUser has no RevokeAllSessionsForUser call,
	//           unlike the deactivation path at line 182.

	admin := adminClient(t)

	// Step 1: Create a temporary user
	tempEmail := fmt.Sprintf("sec004-%d@test.com", time.Now().UnixNano())
	createResp, err := admin.DoJSON(http.MethodPost, "/sobjects/User", map[string]any{
		"Username":  tempEmail,
		"Email":     tempEmail,
		"FirstName": "SEC004",
		"LastName":  "TestUser",
		"Password":  "TempPass123!",
		"ProfileId": "standard_user",
		"IsActive":  true,
	})
	require.NoError(t, err)
	defer createResp.Body.Close()
	createBody := liveapi.ReadBody(t, createResp)

	if createResp.StatusCode != http.StatusCreated {
		t.Skipf("Cannot create test user (status %d): %s", createResp.StatusCode, createBody)
	}

	var tempUser struct{ ID string `json:"id"` }
	require.NoError(t, json.Unmarshal(createBody, &tempUser))
	t.Logf("Created temp user %s (id=%s)", tempEmail, tempUser.ID)

	// Step 2: Login as the temp user to get a token
	cfg := liveapi.LoadConfig(t)
	form := url.Values{}
	form.Set("grant_type", "password")
	form.Set("username", tempEmail)
	form.Set("password", "TempPass123!")

	tokenReq, _ := http.NewRequest(http.MethodPost, cfg.TokenURL,
		strings.NewReader(form.Encode()))
	tokenReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	httpClient := &http.Client{Timeout: 30 * time.Second}
	tokenResp, err := httpClient.Do(tokenReq)
	require.NoError(t, err)
	defer tokenResp.Body.Close()

	if tokenResp.StatusCode != http.StatusOK {
		// Cleanup: delete the user
		admin.Do(http.MethodDelete, "/sobjects/User/"+tempUser.ID, "", nil)
		t.Skipf("Temp user login failed (status %d)", tokenResp.StatusCode)
	}

	var token struct{ AccessToken string `json:"access_token"` }
	require.NoError(t, json.NewDecoder(tokenResp.Body).Decode(&token))
	require.NotEmpty(t, token.AccessToken)

	tempClient := liveapi.NewClientWithToken(cfg, token.AccessToken)

	// Verify token works before deletion
	preResp, err := tempClient.Do(http.MethodGet, "/services/data/", "", nil)
	require.NoError(t, err)
	defer preResp.Body.Close()
	require.Equal(t, http.StatusOK, preResp.StatusCode, "Token should work before deletion")

	// Step 3: Admin deletes the user
	delResp, err := admin.Do(http.MethodDelete, "/sobjects/User/"+tempUser.ID, "", nil)
	require.NoError(t, err)
	defer delResp.Body.Close()
	t.Logf("Delete user response: %d", delResp.StatusCode)

	// Step 4: Verify the deleted user's token is rejected
	postResp, err := tempClient.Do(http.MethodGet, "/services/data/", "", nil)
	require.NoError(t, err)
	defer postResp.Body.Close()

	assert.NotEqual(t, http.StatusOK, postResp.StatusCode,
		"SECURITY BUG: Deleted user's token still works (session not revoked). "+
			"Expected 401/403, got %d", postResp.StatusCode)
}
