<?php

namespace humhub\modules\suggestedfollowing\services;

use humhub\modules\user\models\Follow;
use humhub\modules\user\models\User;

/**
 * Computes follow suggestions for the current user.
 *
 * Algorithm:
 *  1. Collect all users the current user already follows.
 *  2. For each followed user, collect whom they follow (2nd-degree follows).
 *  3. Exclude the current user and anyone already followed.
 *  4. Rank by overlap count descending — i.e. how many people you follow also follow this candidate.
 *
 * @package humhub\modules\suggestedfollowing\services
 */
class SuggestedFollowingService
{
    private User $currentUser;

    public function __construct(User $user)
    {
        $this->currentUser = $user;
    }

    /**
     * Returns ranked SuggestedFollowResult objects up to $limit entries.
     *
     * @param int $limit
     * @return SuggestedFollowResult[]
     */
    public function getSuggestions(int $limit = 5): array
    {
        $currentUserId = $this->currentUser->id;

        $followingIds = $this->getFollowingIds($currentUserId);

        if (empty($followingIds)) {
            return [];
        }

        $overlapCounts = [];

        foreach ($followingIds as $followedId) {
            $theirFollowing = $this->getFollowingIds($followedId);

            foreach ($theirFollowing as $candidateId) {
                if ($candidateId === $currentUserId || in_array($candidateId, $followingIds, true)) {
                    continue;
                }

                if (!isset($overlapCounts[$candidateId])) {
                    $overlapCounts[$candidateId] = 0;
                }
                $overlapCounts[$candidateId]++;
            }
        }

        if (empty($overlapCounts)) {
            return [];
        }

        arsort($overlapCounts);

        $topIds = array_slice(array_keys($overlapCounts), 0, $limit, true);

        $users = User::find()
            ->where(['id' => $topIds])
            ->andWhere(['status' => User::STATUS_ENABLED])
            ->indexBy('id')
            ->all();

        $results = [];

        foreach ($topIds as $userId) {
            if (isset($users[$userId])) {
                $results[] = new SuggestedFollowResult($users[$userId], $overlapCounts[$userId]);
            }
        }

        return $results;
    }

    /**
     * @param int $userId
     * @return int[]
     */
    private function getFollowingIds(int $userId): array
    {
        return (array) Follow::find()
            ->select('object_id')
            ->where([
                'user_id' => $userId,
                'object_model' => User::class,
            ])
            ->column();
    }
}
