package api

import (
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/tidbcloud/aisupport/services/oncall/db"
	"github.com/tidbcloud/aisupport/services/oncall/models"
	"github.com/tidbcloud/aisupport/services/oncall/service"

	"github.com/gin-gonic/gin"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

func setupAPITestDB(t *testing.T) {
	t.Helper()
	gin.SetMode(gin.TestMode)

	var err error
	db.DB, err = gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	if err != nil {
		t.Fatalf("failed to connect sqlite: %v", err)
	}

	err = db.DB.AutoMigrate(&models.Team{}, &models.Engineer{}, &models.EngineerTeam{}, &models.SuperAdmin{}, &models.User{}, &models.UserSession{}, &models.ApiKey{}, &models.AuditLog{})
	if err != nil {
		t.Fatalf("failed to migrate: %v", err)
	}
}

func TestLoginCBRedirectsToFrontendLogin(t *testing.T) {
	setupAPITestDB(t)
	t.Setenv("ONCALL_FRONTEND_URL", "https://oncall.example.test/oncall")

	r := gin.New()
	service.RegisterAuthRoutes(r)

	req := httptest.NewRequest(http.MethodGet, "/loginCB?code=abc123&state=state456", nil)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	if w.Code != http.StatusFound {
		t.Fatalf("expected 302, got %d", w.Code)
	}
	location := w.Header().Get("Location")
	want := "https://oncall.example.test/oncall/login?code=abc123&state=state456"
	if location != want {
		t.Fatalf("redirect location mismatch, want %q got %q", want, location)
	}
}

func TestMeReturnsRBACFlagsFromContextIdentity(t *testing.T) {
	setupAPITestDB(t)
	t.Setenv("AUTH0_ENABLED", "false")
	t.Setenv("DEV_BYPASS_AUTH", "false")
	t.Setenv("ALLOWED_EMAIL_DOMAINS", "pingcap.com")

	if err := db.DB.Create(&models.SuperAdmin{Email: "hu.guo@pingcap.com", CreatedBy: "test"}).Error; err != nil {
		t.Fatalf("create super admin: %v", err)
	}

	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("request_user_email", "hu.guo@pingcap.com")
		c.Set("request_user_name", "hu.guo")
		c.Next()
	})
	service.RegisterAuthRoutes(r)

	for _, path := range []string{"/api/v1/me", "/api/v1/oncall/me"} {
		t.Run(path, func(t *testing.T) {
			req := httptest.NewRequest(http.MethodGet, path, nil)
			w := httptest.NewRecorder()
			r.ServeHTTP(w, req)

			if w.Code != http.StatusOK {
				t.Fatalf("expected 200, got %d body=%s", w.Code, w.Body.String())
			}
			if body := w.Body.String(); body == "" || !(strings.Contains(body, "\"is_super_admin\":true") && strings.Contains(body, "\"can_create_team\":true")) {
				t.Fatalf("expected RBAC flags in response, got %s", body)
			}
		})
	}
}

func TestSharedAuthRoutesSkipSessionAuthentication(t *testing.T) {
	if !shouldSkipAuth("/api/v1/oncall/auth/token", http.MethodPost) {
		t.Fatal("shared token exchange must be reachable without an existing session")
	}
	if !shouldSkipAuth("/api/v1/oncall/auth/logout", http.MethodPost) {
		t.Fatal("shared logout must clear expired sessions")
	}
	if shouldSkipAuth("/api/v1/oncall/teams", http.MethodGet) {
		t.Fatal("shared business APIs must require authentication")
	}
}
