package service_test

import (
	"context"
	"testing"

	"github.com/user-management-system/internal/auth"
	"github.com/user-management-system/internal/domain"
	"github.com/user-management-system/internal/repository"
	"github.com/user-management-system/internal/service"
)

// =============================================================================
// UserService CRUD Tests - Phase 1 (Simplified)
// =============================================================================

func TestUserService_List(t *testing.T) {
	env := setupAuthTestEnv(t)
	if env == nil {
		return
	}
	ctx := context.Background()

	t.Run("List users", func(t *testing.T) {
		// Create multiple users
		for i := 0; i < 3; i++ {
			user := &domain.User{
				Username: "listuser_" + string(rune('a'+i)),
				Password: "$2a$10$dummyhash",
				Status:   domain.UserStatusActive,
			}
			env.userSvc.Create(ctx, user)
		}

		// List
		users, total, err := env.userSvc.List(ctx, 0, 10)
		if err != nil {
			t.Fatalf("List failed: %v", err)
		}
		if len(users) == 0 {
			t.Error("Expected users to be returned")
		}
		if total < 3 {
			t.Errorf("Expected total >= 3, got %d", total)
		}
	})

	t.Run("List users with pagination", func(t *testing.T) {
		users, total, err := env.userSvc.List(ctx, 0, 2)
		if err != nil {
			t.Fatalf("List with pagination failed: %v", err)
		}
		if len(users) > 2 {
			t.Errorf("Expected max 2 users, got %d", len(users))
		}
		if total == 0 {
			t.Error("Expected total > 0")
		}
	})

	t.Run("List users with invalid pagination", func(t *testing.T) {
		// Test with negative offset
		_, _, err := env.userSvc.List(ctx, -1, 10)
		if err != nil {
			t.Errorf("List with negative offset should handle it gracefully: %v", err)
		}

		// Test with zero limit
		_, _, err = env.userSvc.List(ctx, 0, 0)
		if err != nil {
			t.Errorf("List with zero limit should handle it gracefully: %v", err)
		}
	})
}

func TestUserService_GetByID(t *testing.T) {
	env := setupAuthTestEnv(t)
	if env == nil {
		return
	}
	ctx := context.Background()

	t.Run("Get user by ID success", func(t *testing.T) {
		// Create user
		user := &domain.User{
			Username: "getbyid",
			Password: "$2a$10$dummyhash",
			Status:   domain.UserStatusActive,
		}
		err := env.userSvc.Create(ctx, user)
		if err != nil {
			t.Fatalf("Create failed: %v", err)
		}

		// Get by ID
		found, err := env.userSvc.GetByID(ctx, user.ID)
		if err != nil {
			t.Fatalf("GetByID failed: %v", err)
		}
		if found.Username != "getbyid" {
			t.Errorf("Expected username 'getbyid', got %s", found.Username)
		}
	})

	t.Run("Get user by ID not found", func(t *testing.T) {
		_, err := env.userSvc.GetByID(ctx, 99999)
		if err == nil {
			t.Error("Expected error for non-existent user")
		}
	})

	t.Run("Get user by ID with zero ID", func(t *testing.T) {
		_, err := env.userSvc.GetByID(ctx, 0)
		if err == nil {
			t.Error("Expected error for zero ID")
		}
	})
}

func TestUserService_Update(t *testing.T) {
	env := setupAuthTestEnv(t)
	if env == nil {
		return
	}
	ctx := context.Background()

	t.Run("Update user success", func(t *testing.T) {
		// Create user
		user := &domain.User{
			Username: "updateuser",
			Password: "$2a$10$dummyhash",
			Status:   domain.UserStatusActive,
			Nickname: "Old Nickname",
		}
		err := env.userSvc.Create(ctx, user)
		if err != nil {
			t.Fatalf("Create failed: %v", err)
		}

		// Update
		user.Nickname = "New Nickname"
		err = env.userSvc.Update(ctx, user)
		if err != nil {
			t.Fatalf("Update failed: %v", err)
		}

		// Verify
		updated, _ := env.userSvc.GetByID(ctx, user.ID)
		if updated.Nickname != "New Nickname" {
			t.Errorf("Expected nickname 'New Nickname', got %s", updated.Nickname)
		}
	})

	t.Run("Update non-existent user", func(t *testing.T) {
		user := &domain.User{
			ID:       99999,
			Username: "nonexistent",
			Password: "$2a$10$dummyhash",
			Status:   domain.UserStatusActive,
		}
		err := env.userSvc.Update(ctx, user)
		// 实际实现可能静默处理
		_ = err
		t.Logf("Update non-existent user returned: %v", err)
	})
}

func TestUserService_UpdateStatus(t *testing.T) {
	env := setupAuthTestEnv(t)
	if env == nil {
		return
	}
	ctx := context.Background()

	t.Run("Update status success", func(t *testing.T) {
		// Create user
		user := &domain.User{
			Username: "statususer",
			Password: "$2a$10$dummyhash",
			Status:   domain.UserStatusActive,
		}
		err := env.userSvc.Create(ctx, user)
		if err != nil {
			t.Fatalf("Create failed: %v", err)
		}

		// Update status to locked
		err = env.userSvc.UpdateStatus(ctx, user.ID, domain.UserStatusLocked)
		if err != nil {
			t.Fatalf("UpdateStatus failed: %v", err)
		}

		// Verify
		updated, _ := env.userSvc.GetByID(ctx, user.ID)
		if updated.Status != domain.UserStatusLocked {
			t.Errorf("Expected status %d, got %d", domain.UserStatusLocked, updated.Status)
		}
	})

	t.Run("Update status for non-existent user", func(t *testing.T) {
		err := env.userSvc.UpdateStatus(ctx, 99999, domain.UserStatusLocked)
		// 实际实现可能静默处理
		_ = err
		t.Logf("UpdateStatus non-existent user returned: %v", err)
	})
}

func TestUserService_Delete(t *testing.T) {
	env := setupAuthTestEnv(t)
	if env == nil {
		return
	}
	ctx := context.Background()

	t.Run("Delete user success", func(t *testing.T) {
		// Create user
		user := &domain.User{
			Username: "deleteuser",
			Password: "$2a$10$dummyhash",
			Status:   domain.UserStatusActive,
		}
		err := env.userSvc.Create(ctx, user)
		if err != nil {
			t.Fatalf("Create failed: %v", err)
		}

		// Delete
		err = env.userSvc.Delete(ctx, user.ID)
		if err != nil {
			t.Fatalf("Delete failed: %v", err)
		}

		// Verify deletion
		_, err = env.userSvc.GetByID(ctx, user.ID)
		if err == nil {
			t.Error("Expected error for deleted user")
		}
	})

	t.Run("Delete non-existent user", func(t *testing.T) {
		err := env.userSvc.Delete(ctx, 99999)
		// 实际实现可能静默处理
		_ = err
		t.Logf("Delete non-existent user returned: %v", err)
	})
}

func TestUserService_ChangePassword(t *testing.T) {
	env := setupAuthTestEnv(t)
	if env == nil {
		return
	}
	ctx := context.Background()

	t.Run("Change password success", func(t *testing.T) {
		// Create user with known password
		hashedPassword, _ := auth.HashPassword("OldPassword123!")
		user := &domain.User{
			Username: "changepwd",
			Password: hashedPassword,
			Status:   domain.UserStatusActive,
		}
		env.userSvc.Create(ctx, user)

		// Change password
		err := env.userSvc.ChangePassword(ctx, user.ID, "OldPassword123!", "NewPassword456!")
		if err != nil {
			t.Fatalf("ChangePassword failed: %v", err)
		}

		// Verify new password works
		updated, _ := env.userSvc.GetByID(ctx, user.ID)
		if !auth.VerifyPassword(updated.Password, "NewPassword456!") {
			t.Error("New password verification failed")
		}
	})

	t.Run("Change password with wrong old password", func(t *testing.T) {
		hashedPassword, _ := auth.HashPassword("CorrectPassword123!")
		user := &domain.User{
			Username: "wrongpwd",
			Password: hashedPassword,
			Status:   domain.UserStatusActive,
		}
		env.userSvc.Create(ctx, user)

		err := env.userSvc.ChangePassword(ctx, user.ID, "WrongPassword!", "NewPassword456!")
		if err == nil {
			t.Error("Expected error for wrong old password")
		}
	})

	t.Run("Change password for non-existent user", func(t *testing.T) {
		err := env.userSvc.ChangePassword(ctx, 99999, "old", "NewPassword123!")
		if err == nil {
			t.Error("Expected error for non-existent user")
		}
	})

	t.Run("Change password with empty old password", func(t *testing.T) {
		user := &domain.User{
			Username: "emptypwd",
			Password: "$2a$10$dummyhash",
			Status:   domain.UserStatusActive,
		}
		env.userSvc.Create(ctx, user)

		err := env.userSvc.ChangePassword(ctx, user.ID, "", "NewPassword123!")
		if err == nil {
			t.Error("Expected error for empty old password")
		}
	})

	t.Run("Change password with empty new password", func(t *testing.T) {
		hashedPassword, _ := auth.HashPassword("OldPassword123!")
		user := &domain.User{
			Username: "emptynewpwd",
			Password: hashedPassword,
			Status:   domain.UserStatusActive,
		}
		env.userSvc.Create(ctx, user)

		err := env.userSvc.ChangePassword(ctx, user.ID, "OldPassword123!", "")
		if err == nil {
			t.Error("Expected error for empty new password")
		}
	})

	t.Run("Change password with weak new password", func(t *testing.T) {
		hashedPassword, _ := auth.HashPassword("OldPassword123!")
		user := &domain.User{
			Username: "weakpwd",
			Password: hashedPassword,
			Status:   domain.UserStatusActive,
		}
		env.userSvc.Create(ctx, user)

		err := env.userSvc.ChangePassword(ctx, user.ID, "OldPassword123!", "123")
		if err == nil {
			t.Error("Expected error for weak new password")
		}
	})

	t.Run("Change password persists history synchronously", func(t *testing.T) {
		hashedPassword, _ := auth.HashPassword("HistoryOld123!")
		user := &domain.User{
			Username: "historysync",
			Password: hashedPassword,
			Status:   domain.UserStatusActive,
		}
		env.userSvc.Create(ctx, user)

		if err := env.userSvc.ChangePassword(ctx, user.ID, "HistoryOld123!", "HistoryNew456!"); err != nil {
			t.Fatalf("ChangePassword failed: %v", err)
		}

		historyRepo := repository.NewPasswordHistoryRepository(env.db)
		history, err := historyRepo.GetByUserID(ctx, user.ID, 10)
		if err != nil {
			t.Fatalf("GetByUserID failed: %v", err)
		}
		if len(history) == 0 {
			t.Fatal("expected password history to be written synchronously")
		}
		if !auth.VerifyPassword(history[0].PasswordHash, "HistoryNew456!") {
			t.Fatal("latest password history hash does not match new password")
		}
	})
}

func TestUserService_BatchUpdateStatus(t *testing.T) {
	env := setupAuthTestEnv(t)
	if env == nil {
		return
	}
	ctx := context.Background()

	// Create test users
	user1 := &domain.User{Username: "batch1", Password: "$2a$10$hash", Status: domain.UserStatusActive}
	user2 := &domain.User{Username: "batch2", Password: "$2a$10$hash", Status: domain.UserStatusActive}
	env.userSvc.Create(ctx, user1)
	env.userSvc.Create(ctx, user2)

	t.Run("Batch update status", func(t *testing.T) {
		_, err := env.userSvc.BatchUpdateStatus(ctx, &service.BatchUpdateStatusRequest{
			IDs:    []int64{user1.ID, user2.ID},
			Status: domain.UserStatusLocked,
		})
		if err != nil {
			t.Fatalf("BatchUpdateStatus failed: %v", err)
		}

		updated1, _ := env.userSvc.GetByID(ctx, user1.ID)
		if updated1.Status != domain.UserStatusLocked {
			t.Error("Expected user1 status to be locked")
		}
	})
}

func TestUserService_Create(t *testing.T) {
	env := setupAuthTestEnv(t)
	if env == nil {
		return
	}
	ctx := context.Background()

	t.Run("Create user success", func(t *testing.T) {
		email := "create@test.com"
		user := &domain.User{
			Username: "createuser",
			Password: "$2a$10$hash",
			Email:    &email,
			Status:   domain.UserStatusActive,
		}
		err := env.userSvc.Create(ctx, user)
		if err != nil {
			t.Fatalf("Create failed: %v", err)
		}
		if user.ID == 0 {
			t.Error("Expected user ID to be set")
		}
	})

	t.Run("Create user with duplicate username", func(t *testing.T) {
		user1 := &domain.User{Username: "dupcreate", Password: "$2a$10$hash", Status: domain.UserStatusActive}
		env.userSvc.Create(ctx, user1)

		user2 := &domain.User{Username: "dupcreate", Password: "$2a$10$hash", Status: domain.UserStatusActive}
		err := env.userSvc.Create(ctx, user2)
		if err == nil {
			t.Error("Expected error for duplicate username")
		}
	})
}

func TestUserService_GetByEmail(t *testing.T) {
	env := setupAuthTestEnv(t)
	if env == nil {
		return
	}
	ctx := context.Background()

	t.Run("Get user by email", func(t *testing.T) {
		email := "getbyemail@test.com"
		user := &domain.User{
			Username: "emailuser",
			Password: "$2a$10$hash",
			Email:    &email,
			Status:   domain.UserStatusActive,
		}
		env.userSvc.Create(ctx, user)

		found, err := env.userSvc.GetByEmail(ctx, "getbyemail@test.com")
		if err != nil {
			t.Fatalf("GetByEmail failed: %v", err)
		}
		if found.Username != "emailuser" {
			t.Errorf("Expected username 'emailuser', got %s", found.Username)
		}
	})

	t.Run("Get user by non-existent email", func(t *testing.T) {
		_, err := env.userSvc.GetByEmail(ctx, "nonexistent@test.com")
		if err == nil {
			t.Error("Expected error for non-existent email")
		}
	})
}
