<?php

declare(strict_types=1);

namespace Seka\Portal\Modul\Vzdelavanie\Services\Pouzivatel\Testovanie;

use Seka\Portal\Modul\Vzdelavanie\Events\Testovanie\Frontend\TestVyhodnotenie;
use Seka\Portal\Modul\Vzdelavanie\Models\Pouzivatel\Testovanie\Odpoved;
use Seka\Portal\Modul\Vzdelavanie\Models\Pouzivatel\Testovanie\Otazka;
use Seka\Portal\Modul\Vzdelavanie\Models\Pouzivatel\Testovanie\StavVyhodnoteniaTestuEnum;
use Seka\Portal\Modul\Vzdelavanie\Models\Pouzivatel\Testovanie\Test;
use Seka\Portal\Modul\Vzdelavanie\Services\Pouzivatel\Testovanie\Exceptions\TestUzBolVyhodnotenyException;

/**
 * Class VyhodnotenieTestu
 *
 * @package Seka\Portal\Modul\Vzdelavanie\Services\Pouzivatel\Testovanie
 */
final class VyhodnotenieTestu
{
    /**
     * @param \Seka\Portal\Modul\Vzdelavanie\Models\Pouzivatel\Testovanie\Test $test
     *
     * @return \Seka\Portal\Modul\Vzdelavanie\Models\Pouzivatel\Testovanie\Test
     * @throws \Seka\Portal\Modul\Vzdelavanie\Services\Pouzivatel\Testovanie\Exceptions\TestUzBolVyhodnotenyException
     * @throws \Throwable
     */
    public static function vyhodnotenie(Test $test): Test
    {
        $pocetOtazokBezOdpovede = 0;
        $pocetSpravneZodpovedanychOtazok = 0;
        $pocetNespravneZodpovedanychOtazok = 0;

        if ($test->jeVyhodnoteny()) {
            throw new TestUzBolVyhodnotenyException();
        }

        $test
            ->otazky()
            ->with('odpovede')
            ->get()
            ->each(
                function (Otazka $otazka) use (
                    &$pocetSpravneZodpovedanychOtazok,
                    &$pocetNespravneZodpovedanychOtazok,
                    &
                    $pocetOtazokBezOdpovede,
                ) {
                    $spravneZodpovedanaOtazka = false;
                    $pocetSpravnychOdpovedi = 0;
                    $pocetNespravnychOdpovedi = 0;
                    $zodpovedanaOtazka = false;

                    $otazka->odpovede
                        ->each(
                            function (Odpoved $odpoved) use (
                                &$pocetSpravnychOdpovedi,
                                &$pocetNespravnychOdpovedi,
                                &
                                $spravneZodpovedanaOtazka,
                                &$zodpovedanaOtazka,
                            ) {
                                if ($odpoved->jeZvolena()) {
                                    if ($odpoved->jeSpravna()) {
                                        $pocetSpravnychOdpovedi = ++$pocetSpravnychOdpovedi;
                                    } else {
                                        $pocetNespravnychOdpovedi = ++$pocetNespravnychOdpovedi;
                                    }

                                    $zodpovedanaOtazka = true;
                                } else {
                                    if ($odpoved->jeSpravna()) {
                                        $pocetNespravnychOdpovedi = ++$pocetNespravnychOdpovedi;
                                    }
                                }
                            },
                        );

                    if ($pocetNespravnychOdpovedi === 0) {
                        $spravneZodpovedanaOtazka = VyhodnotenieOtazky::vyhodnot($otazka, $pocetSpravnychOdpovedi);
                    }

                    if ($pocetNespravnychOdpovedi > 0 && $zodpovedanaOtazka === true) {
                        $pocetNespravneZodpovedanychOtazok = ++$pocetNespravneZodpovedanychOtazok;
                    }

                    if (true === $spravneZodpovedanaOtazka) {
                        $pocetSpravneZodpovedanychOtazok = ++$pocetSpravneZodpovedanychOtazok;
                    }

                    if (false === $zodpovedanaOtazka) {
                        $pocetOtazokBezOdpovede = ++$pocetOtazokBezOdpovede;
                    }
                },
            );

        $test->fill([
            'stav' => StavVyhodnoteniaTestuEnum::VYHODNOTENY,
            'pocet_otazok_bez_odpovede' => $pocetOtazokBezOdpovede,
            'casova_znacka_vyhodnotenia' => now(),
            'pocet_spravne_zodpovedanych_otazok' => $pocetSpravneZodpovedanychOtazok,
            'pocet_nespravne_zodpovedanych_otazok' => $pocetNespravneZodpovedanychOtazok,
        ])->saveOrFail();

        // zaznamenat udalost vyhodnotenia testu
        event(new TestVyhodnotenie($test));

        return $test->refresh();
    }
}
