package handlers_test

// auth_middleware_leak_test.go — Pre-fix tests for JWT secret leak in WebAuthMiddleware.
//
// BUG F-A3-11 CRITICAL: WebAuthMiddleware (auth.go:128) prints the JWT signing
// secret to stdout on every validation failure:
//   fmt.Printf("🔓 JWT validation failed: %v (secret: %s)\n", err, h.jwtSecret)
//
// Violations:
//   1. Secret in log output — any log collector captures the signing key
//   2. Emoji in log output — violates ETHOS #1 log format requirement
//   3. Log format wrong — must be [TAG] [system] [component] per ETHOS #1
//
// Tests 1.1-1.3 currently FAIL (bug present). They will PASS after the fix.
//
// Run: cd aggregator-server && go test ./internal/api/handlers/... -v -run TestWebAuthMiddleware

import (
	"bytes"
	"io"
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"

	"github.com/Fimeg/RedFlag/aggregator-server/internal/api/handlers"
	"github.com/gin-gonic/gin"
)

func init() {
	gin.SetMode(gin.TestMode)
}

// ---------------------------------------------------------------------------
// Test 1.1 — WebAuthMiddleware does NOT log the JWT secret
//
// Category: FAIL-NOW / PASS-AFTER-FIX
//
// BUG F-A3-11: auth.go:128 prints h.jwtSecret directly to stdout.
// Any log collector (Docker logs, journald, CloudWatch) captures this secret.
// An attacker with log access can forge arbitrary admin tokens.
// ---------------------------------------------------------------------------

func TestWebAuthMiddlewareDoesNotLogSecret(t *testing.T) {
	testSecret := "test-secret-12345"
	authHandler := handlers.NewAuthHandler(testSecret, nil)

	router := gin.New()
	router.Use(authHandler.WebAuthMiddleware())
	router.GET("/test", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"ok": true})
	})

	// Capture stdout during middleware execution
	oldStdout := os.Stdout
	r, w, err := os.Pipe()
	if err != nil {
		t.Fatalf("failed to create pipe: %v", err)
	}
	os.Stdout = w

	// Send request with an invalid JWT (valid format, wrong signature)
	req := httptest.NewRequest("GET", "/test", nil)
	req.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMSJ9.invalidsig")
	rec := httptest.NewRecorder()
	router.ServeHTTP(rec, req)

	w.Close()
	os.Stdout = oldStdout

	var buf bytes.Buffer
	io.Copy(&buf, r)
	captured := buf.String()

	// The secret MUST NOT appear in stdout
	if strings.Contains(captured, testSecret) {
		t.Errorf("[ERROR] [server] [auth] WebAuthMiddleware leaked JWT secret to stdout.\n"+
			"BUG F-A3-11: auth.go:128 prints h.jwtSecret on validation failure.\n"+
			"Captured output contains: %q\n"+
			"After fix: remove secret from log output entirely.", testSecret)
	}

	// Confirm the request was still rejected
	if rec.Code != http.StatusUnauthorized {
		t.Errorf("[ERROR] [server] [auth] expected 401 for invalid token, got %d", rec.Code)
	}
}

// ---------------------------------------------------------------------------
// Test 1.2 — WebAuthMiddleware log output has no emoji characters
//
// Category: FAIL-NOW / PASS-AFTER-FIX
//
// BUG F-A3-11: auth.go:128 uses "🔓" (U+1F513) in log output.
// ETHOS #1 requires [TAG] [system] [component] format, no emojis.
// ---------------------------------------------------------------------------

func TestWebAuthMiddlewareLogFormatHasNoEmoji(t *testing.T) {
	authHandler := handlers.NewAuthHandler("emoji-test-secret", nil)

	router := gin.New()
	router.Use(authHandler.WebAuthMiddleware())
	router.GET("/test", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"ok": true})
	})

	oldStdout := os.Stdout
	r, w, _ := os.Pipe()
	os.Stdout = w

	req := httptest.NewRequest("GET", "/test", nil)
	req.Header.Set("Authorization", "Bearer invalid-token")
	rec := httptest.NewRecorder()
	router.ServeHTTP(rec, req)

	w.Close()
	os.Stdout = oldStdout

	var buf bytes.Buffer
	io.Copy(&buf, r)
	captured := buf.String()

	// Check for emoji characters (Unicode symbols above U+1F300)
	hasEmoji := false
	for _, ch := range captured {
		if ch >= 0x1F300 || (ch >= 0x2600 && ch <= 0x27BF) {
			hasEmoji = true
			t.Errorf("[ERROR] [server] [auth] emoji character found in log output: U+%04X\n"+
				"BUG F-A3-11: auth.go:128 uses emoji in log. ETHOS #1 violation.\n"+
				"After fix: use [WARNING] [server] [auth] format.", ch)
			break
		}
	}

	// Also check for the specific emoji used
	if strings.Contains(captured, "\U0001F513") {
		if !hasEmoji {
			t.Errorf("[ERROR] [server] [auth] lock emoji U+1F513 found in log output")
		}
	}

	// Check that the word "secret" does not appear
	if strings.Contains(strings.ToLower(captured), "secret") {
		t.Errorf("[ERROR] [server] [auth] word 'secret' found in log output")
	}

	_ = rec // ensure request completed
}

// ---------------------------------------------------------------------------
// Test 1.3 — WebAuthMiddleware log format is ETHOS-compliant
//
// Category: FAIL-NOW / PASS-AFTER-FIX
//
// BUG F-A3-11: Log format must be [TAG] [system] [component] message.
// Current output: "🔓 JWT validation failed: ... (secret: ...)"
// Expected: "[WARNING] [server] [auth] jwt_validation_failed error=..."
// ---------------------------------------------------------------------------

func TestWebAuthMiddlewareLogFormatCompliant(t *testing.T) {
	authHandler := handlers.NewAuthHandler("format-test-secret", nil)

	router := gin.New()
	router.Use(authHandler.WebAuthMiddleware())
	router.GET("/test", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"ok": true})
	})

	oldStdout := os.Stdout
	r, w, _ := os.Pipe()
	os.Stdout = w

	req := httptest.NewRequest("GET", "/test", nil)
	req.Header.Set("Authorization", "Bearer invalid-jwt-token")
	rec := httptest.NewRecorder()
	router.ServeHTTP(rec, req)

	w.Close()
	os.Stdout = oldStdout

	var buf bytes.Buffer
	io.Copy(&buf, r)
	captured := buf.String()

	if captured == "" {
		// No output is acceptable (middleware can log to logger instead of stdout)
		t.Log("[INFO] [server] [auth] no stdout output produced (acceptable)")
		return
	}

	// If output exists, it must follow ETHOS format
	lines := strings.Split(strings.TrimSpace(captured), "\n")
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}
		// Must start with [TAG] pattern
		if !strings.HasPrefix(line, "[") {
			t.Errorf("[ERROR] [server] [auth] log line does not follow [TAG] format: %q\n"+
				"BUG F-A3-11: expected [WARNING] [server] [auth] or [ERROR] [server] [auth]", line)
		}
		// Must not contain the secret
		if strings.Contains(line, "format-test-secret") {
			t.Errorf("[ERROR] [server] [auth] log line contains JWT secret")
		}
	}

	_ = rec
}
