package service

import (
	"context"
	"testing"

	"github.com/user-management-system/internal/auth"
	"github.com/user-management-system/internal/cache"
	"github.com/user-management-system/internal/domain"
	"github.com/user-management-system/internal/repository"
	gormsqlite "gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// =============================================================================
// Auth Admin Bootstrap Internal Tests
// =============================================================================

func setupBootstrapInternalTestEnv(t *testing.T) (*AuthService, *gorm.DB) {
	t.Helper()

	db, err := gorm.Open(gormsqlite.New(gormsqlite.Config{
		DriverName: "sqlite",
		DSN:        "file:bootstrap_internal_test?mode=memory&cache=shared",
	}), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Silent),
	})
	if err != nil {
		t.Fatalf("failed to connect database: %v", err)
	}

	if err := db.AutoMigrate(&domain.User{}, &domain.Role{}, &domain.UserRole{}); err != nil {
		t.Fatalf("failed to migrate: %v", err)
	}

	// Create admin role
	adminRole := &domain.Role{
		Name:   "管理员",
		Code:   "admin",
		Status: domain.RoleStatusEnabled,
	}
	db.Create(adminRole)

	userRepo := repository.NewUserRepository(db)
	userRoleRepo := repository.NewUserRoleRepository(db)
	roleRepo := repository.NewRoleRepository(db)
	socialRepo, _ := repository.NewSocialAccountRepository(db)
	jwtManager, _ := auth.NewJWTWithOptions(auth.JWTOptions{
		HS256Secret:        "test-secret-for-bootstrap",
		AccessTokenExpire:  15 * 60 * 1000 * 1000 * 1000,
		RefreshTokenExpire: 7 * 24 * 60 * 60 * 1000 * 1000 * 1000,
	})

	l1Cache := cache.NewL1Cache()
	l2Cache := cache.NewRedisCache(false)
	cacheManager := cache.NewCacheManager(l1Cache, l2Cache)

	svc := NewAuthService(userRepo, socialRepo, jwtManager, cacheManager, 8, 5, 15*60*1000*1000*1000)
	svc.SetRoleRepositories(userRoleRepo, roleRepo)

	return svc, db
}

func TestBootstrapAdmin_Internal(t *testing.T) {
	svc, db := setupBootstrapInternalTestEnv(t)
	ctx := context.Background()

	t.Run("BootstrapAdmin with nil request", func(t *testing.T) {
		_, err := svc.BootstrapAdmin(ctx, nil, "127.0.0.1")
		if err == nil {
			t.Error("Expected error for nil request")
		}
	})

	t.Run("BootstrapAdmin with empty username", func(t *testing.T) {
		req := &BootstrapAdminRequest{
			Username: "",
			Password: "Admin123!",
		}
		_, err := svc.BootstrapAdmin(ctx, req, "127.0.0.1")
		if err == nil {
			t.Error("Expected error for empty username")
		}
	})

	t.Run("BootstrapAdmin with empty password", func(t *testing.T) {
		req := &BootstrapAdminRequest{
			Username: "testadmin",
			Password: "",
		}
		_, err := svc.BootstrapAdmin(ctx, req, "127.0.0.1")
		if err == nil {
			t.Error("Expected error for empty password")
		}
	})

	t.Run("BootstrapAdmin with weak password", func(t *testing.T) {
		req := &BootstrapAdminRequest{
			Username: "testadmin",
			Password: "123",
		}
		_, err := svc.BootstrapAdmin(ctx, req, "127.0.0.1")
		if err == nil {
			t.Error("Expected error for weak password")
		}
	})

	t.Run("BootstrapAdmin success", func(t *testing.T) {
		// Clean up
		db.Exec("DELETE FROM user_roles")
		db.Exec("DELETE FROM users")

		req := &BootstrapAdminRequest{
			Username: "newadmin",
			Password: "Admin123!",
			Email:    "newadmin@test.com",
			Nickname: "New Admin",
		}
		resp, err := svc.BootstrapAdmin(ctx, req, "127.0.0.1")
		if err != nil {
			t.Fatalf("BootstrapAdmin failed: %v", err)
		}
		if resp.AccessToken == "" {
			t.Error("Expected access token")
		}
		if resp.User.Username != "newadmin" {
			t.Errorf("Expected username 'newadmin', got %s", resp.User.Username)
		}
	})

	t.Run("BootstrapAdmin with duplicate username", func(t *testing.T) {
		req := &BootstrapAdminRequest{
			Username: "dupadmin",
			Password: "Admin123!",
		}
		// First create
		svc.BootstrapAdmin(ctx, req, "127.0.0.1")
		// Second create should fail
		_, err := svc.BootstrapAdmin(ctx, req, "127.0.0.1")
		if err == nil {
			t.Error("Expected error for duplicate username")
		}
	})

	t.Run("BootstrapAdmin with duplicate email", func(t *testing.T) {
		// Clean up
		db.Exec("DELETE FROM user_roles WHERE user_id IN (SELECT id FROM users WHERE username LIKE 'emailtest%')")
		db.Exec("DELETE FROM users WHERE username LIKE 'emailtest%'")

		req1 := &BootstrapAdminRequest{
			Username: "emailtest1",
			Password: "Admin123!",
			Email:    "samemail@test.com",
		}
		svc.BootstrapAdmin(ctx, req1, "127.0.0.1")

		req2 := &BootstrapAdminRequest{
			Username: "emailtest2",
			Password: "Admin123!",
			Email:    "samemail@test.com",
		}
		_, err := svc.BootstrapAdmin(ctx, req2, "127.0.0.1")
		if err == nil {
			t.Error("Expected error for duplicate email")
		}
	})

	t.Run("BootstrapAdmin when bootstrap unavailable", func(t *testing.T) {
		// Create an existing admin to make bootstrap unavailable
		db.Exec("DELETE FROM user_roles")
		db.Exec("DELETE FROM users")

		req := &BootstrapAdminRequest{
			Username: "firstadmin",
			Password: "Admin123!",
		}
		svc.BootstrapAdmin(ctx, req, "127.0.0.1")

		// Now try again - should fail because admin already exists
		req2 := &BootstrapAdminRequest{
			Username: "secondadmin",
			Password: "Admin123!",
		}
		_, err := svc.BootstrapAdmin(ctx, req2, "127.0.0.1")
		if err == nil {
			t.Error("Expected error when bootstrap unavailable")
		}
	})
}

func TestBootstrapAdmin_NilService(t *testing.T) {
	var nilSvc *AuthService
	ctx := context.Background()

	t.Run("nil service returns error", func(t *testing.T) {
		req := &BootstrapAdminRequest{
			Username: "admin",
			Password: "Admin123!",
		}
		_, err := nilSvc.BootstrapAdmin(ctx, req, "127.0.0.1")
		if err == nil {
			t.Error("Expected error for nil service")
		}
	})
}

func TestIsAdminBootstrapRequired(t *testing.T) {
	svc, db := setupBootstrapInternalTestEnv(t)
	ctx := context.Background()

	t.Run("returns true when no admin exists", func(t *testing.T) {
		db.Exec("DELETE FROM user_roles")
		db.Exec("DELETE FROM users")

		required := svc.IsAdminBootstrapRequired(ctx)
		if !required {
			t.Error("Expected IsAdminBootstrapRequired to return true when no admin exists")
		}
	})

	t.Run("returns false when admin exists", func(t *testing.T) {
		db.Exec("DELETE FROM user_roles")
		db.Exec("DELETE FROM users")

		req := &BootstrapAdminRequest{
			Username: "bootstrapadmin",
			Password: "Admin123!",
		}
		svc.BootstrapAdmin(ctx, req, "127.0.0.1")

		required := svc.IsAdminBootstrapRequired(ctx)
		if required {
			t.Error("Expected IsAdminBootstrapRequired to return false when admin exists")
		}
	})

	t.Run("nil service returns false", func(t *testing.T) {
		var nilSvc *AuthService
		required := nilSvc.IsAdminBootstrapRequired(ctx)
		if required {
			t.Error("Expected IsAdminBootstrapRequired to return false for nil service")
		}
	})
}
