<?php

namespace App\Services\Ranking;

use App\Contracts\CatalogProductRanker;

class HeuristicCatalogProductRanker implements CatalogProductRanker
{
    /**
     * @param  list<array<string, mixed>>  $candidates
     * @return list<array<string, mixed>>
     */
    public function rank(
        array $candidates,
        string $category = '',
        string $subcategory = '',
        ?string $notes = null,
    ): array {
        if ($candidates === []) {
            return [];
        }

        $limit = max(1, (int) config('scraping.ranking.limit', 10));

        $sorted = $candidates;
        usort($sorted, fn (array $left, array $right): int => $this->compareCandidates($left, $right));

        $ranked = [];

        foreach (array_slice($sorted, 0, $limit) as $index => $candidate) {
            $ranked[] = array_merge($candidate, [
                'rank' => $index + 1,
                'selection_reason' => $this->selectionReason($candidate),
                'best_for' => $index === 0 ? 'Best Overall' : null,
                'ranking_source' => 'heuristic',
            ]);
        }

        return $ranked;
    }

    /**
     * @param  array<string, mixed>  $left
     * @param  array<string, mixed>  $right
     */
    private function compareCandidates(array $left, array $right): int
    {
        if (config('google-ads.ranking_use_keywords', true)) {
            $keywordComparison = (int) ($right['keyword_search_volume'] ?? 0) <=> (int) ($left['keyword_search_volume'] ?? 0);

            if ($keywordComparison !== 0) {
                return $keywordComparison;
            }
        }

        $reviewComparison = (int) ($right['review_count'] ?? 0) <=> (int) ($left['review_count'] ?? 0);

        if ($reviewComparison !== 0) {
            return $reviewComparison;
        }

        return (float) ($right['rating'] ?? 0) <=> (float) ($left['rating'] ?? 0);
    }

    /**
     * @param  array<string, mixed>  $candidate
     */
    private function selectionReason(array $candidate): string
    {
        $note = trim((string) ($candidate['popularity_note'] ?? ''));

        if ($note !== '') {
            return $note;
        }

        $parts = [];

        if (filled($candidate['rating'] ?? null)) {
            $parts[] = "{$candidate['rating']} stars";
        }

        if (filled($candidate['review_count'] ?? null)) {
            $parts[] = "{$candidate['review_count']} reviews";
        }

        if (filled($candidate['keyword_search_volume'] ?? null)) {
            $parts[] = number_format((int) $candidate['keyword_search_volume']).' monthly searches';
        }

        return $parts !== [] ? implode(', ', $parts) : 'Strong listing-page signals.';
    }
}
