package service

import (
	"context"
	"testing"
	"time"

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

// =============================================================================
// Stats Service Internal Tests
// =============================================================================

// mockStatsUserRepoInternal mocks user repository for stats tests
type mockStatsUserRepoInternal struct {
	totalUsers    int64
	activeUsers   int64
	inactiveUsers int64
	lockedUsers   int64
	disabledUsers int64
	newUsersToday int64
}

func (m *mockStatsUserRepoInternal) List(ctx context.Context, offset, limit int) ([]*domain.User, int64, error) {
	return nil, m.totalUsers, nil
}

func (m *mockStatsUserRepoInternal) ListByStatus(ctx context.Context, status domain.UserStatus, offset, limit int) ([]*domain.User, int64, error) {
	switch status {
	case domain.UserStatusActive:
		return nil, m.activeUsers, nil
	case domain.UserStatusInactive:
		return nil, m.inactiveUsers, nil
	case domain.UserStatusLocked:
		return nil, m.lockedUsers, nil
	case domain.UserStatusDisabled:
		return nil, m.disabledUsers, nil
	}
	return nil, 0, nil
}

func (m *mockStatsUserRepoInternal) ListCreatedAfter(ctx context.Context, since time.Time, offset, limit int) ([]*domain.User, int64, error) {
	return nil, m.newUsersToday, nil
}

// mockStatsLoginLogRepoInternal mocks login log repository for stats tests
type mockStatsLoginLogRepoInternal struct {
	successCount int64
	failedCount  int64
	weekCount    int64
}

func (m *mockStatsLoginLogRepoInternal) CountByResultSince(ctx context.Context, success bool, since time.Time) (int64, error) {
	if success {
		return m.successCount, nil
	}
	return m.failedCount, nil
}

func TestStatsService_GetDashboardStats_Internal(t *testing.T) {
	userRepo := &mockStatsUserRepoInternal{
		totalUsers:    100,
		activeUsers:   80,
		inactiveUsers: 10,
		lockedUsers:   5,
		disabledUsers: 5,
		newUsersToday: 3,
	}
	loginLogRepo := &mockStatsLoginLogRepoInternal{
		successCount: 50,
		failedCount:  5,
		weekCount:    200,
	}

	svc := NewStatsService(userRepo, loginLogRepo)
	ctx := context.Background()

	stats, err := svc.GetDashboardStats(ctx)
	if err != nil {
		t.Fatalf("GetDashboardStats failed: %v", err)
	}

	if stats.Users.TotalUsers != 100 {
		t.Errorf("Expected TotalUsers=100, got %d", stats.Users.TotalUsers)
	}
	if stats.Logins.LoginsTodaySuccess != 50 {
		t.Errorf("Expected LoginsTodaySuccess=50, got %d", stats.Logins.LoginsTodaySuccess)
	}
	if stats.Logins.LoginsTodayFailed != 5 {
		t.Errorf("Expected LoginsTodayFailed=5, got %d", stats.Logins.LoginsTodayFailed)
	}
}

func TestStatsService_GetDashboardStats_NilLoginLogRepo(t *testing.T) {
	userRepo := &mockStatsUserRepoInternal{
		totalUsers:    50,
		activeUsers:   40,
		inactiveUsers: 5,
		lockedUsers:   3,
		disabledUsers: 2,
		newUsersToday: 2,
	}

	svc := NewStatsService(userRepo, nil)
	ctx := context.Background()

	stats, err := svc.GetDashboardStats(ctx)
	if err != nil {
		t.Fatalf("GetDashboardStats failed: %v", err)
	}

	if stats.Users.TotalUsers != 50 {
		t.Errorf("Expected TotalUsers=50, got %d", stats.Users.TotalUsers)
	}
	// Login stats should be 0 when loginLogRepo is nil
	if stats.Logins.LoginsTodaySuccess != 0 {
		t.Errorf("Expected LoginsTodaySuccess=0, got %d", stats.Logins.LoginsTodaySuccess)
	}
}

func TestDaysAgo(t *testing.T) {
	result := daysAgo(0)
	if result.After(time.Now()) {
		t.Error("daysAgo(0) should not be in the future")
	}

	result = daysAgo(7)
	if result.After(time.Now()) {
		t.Error("daysAgo(7) should not be in the future")
	}
}
