<?php

namespace App\Services\Quiz;

use App\Enums\NotificationType;
use App\Models\Badge;
use App\Models\User;

class BadgeService
{
    public static function getCriteriaWithDescriptions(): array
    {
        return array_reduce(self::criteria(), function ($acc, $item) {
            $acc[$item['type']] = $item['description'];

            return $acc;
        }, []);
    }

    /**
     * Return an array of strings representing the different types of badge criteria.
     *
     * @return array<string>
     */
    public static function getCriteriaTypes(): array
    {
        return array_keys(self::getCriteriaWithClass());
    }

    public function checkAndAssignBadges(User $user)
    {
        $badgesAssigned = false;
        $badges = Badge::all();
        foreach ($badges as $badge) {
            $criteria = $badge->criteria;
            $evaluator = $this->getEvaluator($criteria['type']);

            if ($evaluator && ! $user->badges()->where('slug', $badge->slug)->exists() && $evaluator->isMet($user, $criteria)) {

                $user->badges()->attach($badge->id, [
                    'earned_at' => now(),
                ]);

                $badgesAssigned = true;

                $user->notify(new \App\Notifications\UserAutoNotification(NotificationType::BADGE_EARNED, [
                    'badge_name' => $badge->title,
                ]));
            }
        }

        return $badgesAssigned;
    }

    /**
     * Get evaluator for a given badge type.
     */
    private function getEvaluator(string $type): mixed
    {
        $criteria = self::getCriteriaWithClass();

        return $criteria[$type] ?? null;
    }

    /**
     * Returns an array mapping badge types to evaluator instances.
     *
     * @return array<string, mixed>
     */
    private static function getCriteriaWithClass(): array
    {
        return array_reduce(self::criteria(), function ($acc, $value) {
            $acc[$value['type']] = $value['class'];

            return $acc;
        }, []);
    }

    private static function criteria(): array
    {
        return array_map(function ($badge) {
            return [
                'type' => $badge['criteria']['type'],
                'description' => $badge['description'],
                'class' => $badge['class'],
            ];
        }, self::badges());
    }

    /**
     * Returns the defined badge types with their evaluator class and description.
     *
     * @return array<int, array<string, mixed>>
     */
    public static function badges(): array
    {

        return [
            [
                'title' => 'Quiz Master',
                'slug' => 'quiz-master',
                'description' => 'Scored 90% or above in 10 quizzes.',
                'icon' => '/assets/client/badges/quiz_master.png',
                'class' => new Criteria\HighScoreQuizzes,
                'criteria' => [
                    'type' => 'high_score_quizzes',
                    'value' => 10,
                ],
            ],
            [
                'title' => 'Accuracy Ace',
                'slug' => 'accuracy-ace',
                'description' => 'Achieved perfect score in 5 consecutive quizzes.',
                'icon' => '/assets/client/badges/accuracy_ace.png',
                'class' => new Criteria\PerfectConsecutive,
                'criteria' => [
                    'type' => 'perfect_consecutive',
                    'value' => 5,
                ],
            ],
            [
                'title' => 'Fast Thinker',
                'slug' => 'fast-thinker',
                'description' => 'Completed a quiz in record time with 80% accuracy or higher.',
                'icon' => '/assets/client/badges/fast_thinker.png',
                'class' => new Criteria\FastCompletionAccuracy,
                'criteria' => [
                    'type' => 'fast_completion_accuracy',
                    'value' => 80,
                ],
            ],
            [
                'title' => 'Top Performer',
                'slug' => 'top-performer',
                'description' => 'Secured a spot in the top 3 on the leaderboard.',
                'icon' => '/assets/client/badges/top_performer.png',
                'class' => new Criteria\LeaderboardRank,
                'criteria' => [
                    'type' => 'leaderboard_rank',
                    'value' => 3,
                ],
            ],
            [
                'title' => 'Quiz Enthusiast',
                'slug' => 'quiz-enthusiast',
                'description' => 'Attempted 50 quizzes.',
                'icon' => '/assets/client/badges/quiz_enthusiast.png',
                'class' => new Criteria\QuizzesAttempted,
                'criteria' => [
                    'type' => 'quizzes_attempted',
                    'value' => 50,
                ],
            ],
            [
                'title' => 'Daily Streak Hero',
                'slug' => 'daily-streak-hero',
                'description' => 'Completed quizzes for 7 consecutive days.',
                'icon' => '/assets/client/badges/daily_streak_hero.png',
                'class' => new Criteria\ConsecutiveDays,
                'criteria' => [
                    'type' => 'consecutive_days',
                    'value' => 7,
                ],
            ],
            [
                'title' => 'Century Club',
                'slug' => 'century-club',
                'description' => 'Completed 100 quizzes.',
                'icon' => '/assets/client/badges/century_club.png',
                'class' => new Criteria\QuizzesCompleted,
                'criteria' => [
                    'type' => 'quizzes_completed',
                    'value' => 100,
                ],
            ],
        ];
    }
}
