<?php

declare(strict_types=1);

namespace Seka\Portal\Modul\Terminy\Livewire\Frontend\Registracie\Components\MoznostiUdalosti\Components;

use Exception;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Livewire\Component;
use Seka\Portal\Modul\Terminy\Actions\CreateRegistration;
use Seka\Portal\Modul\Terminy\Entities\Registracia\Registracia;
use Seka\Portal\Modul\Terminy\Entities\Registracia\ValueObjects\ZoznamZvolenychMoznostiUdalostiValueObject;
use Seka\Portal\Modul\Terminy\Entities\Udalost\Udalost;
use Seka\Portal\Modul\Terminy\Entities\Udalost\ValueObjects\MoznostUdalostiValueObject;
use Seka\Portal\Modul\Terminy\Entities\Udalost\ValueObjects\ZoznamMoznostiUdalostiValueObject;
use Seka\Portal\Modul\Terminy\Exceptions\TerminyException;

/**
 * Class RegistraciaMoznostiUdalostiForm
 *
 * @package Seka\Portal\Modul\Terminy\Livewire\Frontend\Registracie\Components\MoznostiUdalosti\Components
 */
final class Form extends Component
{
    use AuthorizesRequests;

    /**
     * @var \Seka\Portal\Modul\Terminy\Entities\Udalost\Udalost
     */
    public Udalost $udalost;

    /**
     * @var array
     */
    public array $moznosti = [];

    /**
     * @var bool
     */
    public bool $acceptChoices = false;

    /**
     * @param \Seka\Portal\Modul\Terminy\Entities\Udalost\Udalost $udalost
     *
     * @return void
     */
    public function mount(Udalost $udalost): void
    {
        $this->udalost->moznosti->each(function (ZoznamMoznostiUdalostiValueObject $zoznamMoznostiUdalostiValueObject) {
            $this->moznosti[$zoznamMoznostiUdalostiValueObject->getKod()] = null;
        });
        $this->udalost = $udalost;
    }

    /**
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View|mixed
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function render()
    {
        return view('Terminy::livewire.frontend.registracie.components.moznosti-udalosti.form');
    }

    /**
     * @return bool
     */
    public function getChoosedAllOptionsProperty(): bool
    {
        return collect($this->moznosti)->filter(fn($item) => is_null($item))->isEmpty();
    }

    /**
     * @param \Seka\Portal\Modul\Terminy\Actions\CreateRegistration $createRegistration
     *
     * @return \Illuminate\Http\RedirectResponse
     * @throws \Illuminate\Auth\Access\AuthorizationException
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     * @throws \Throwable
     */
    public function createRegistration(CreateRegistration $createRegistration)
    {
        try {
            $this->authorize('terminy.registracie.vytvorit');

            $pouzivatel = auth()->user();
            $pracovisko = auth()->user()->pracovisko;
            $registracia = new Registracia();
            $registracia->pouzivatel()->associate($pouzivatel);

            $registracia->moznosti = $this->makeListOfMoznostiValueObjects();

            DB::beginTransaction();
            $createRegistration::execute($this->udalost, $pouzivatel, $pracovisko, $registracia);
            DB::commit();

            flash()->overlay('Registrácia používateľa na udalosť bola úspešná.', 'Hlásenie')->success();
        } catch (ModelNotFoundException $e) {
            flash()->overlay('Udalosť nebola nájdená.', 'Hlásenie')->warning();
        } catch (TerminyException $e) {
            flash()->overlay($e->getMessage(), 'Hlásenie')->warning();
        } catch (Exception $e) {
            DB::rollBack();
            Log::error($e->getMessage(), $e->getTrace());
            flash()->overlay('Chyba', 'Hlásenie')->error();
        } finally {
            return redirect()
                ->route(
                    'modul.terminy.frontend.udalosti.udalost.show',
                    $this->udalost,
                );
        }
    }

    /**
     * @return \Illuminate\Support\Collection
     */
    private function makeListOfMoznostiValueObjects(): Collection
    {
        return collect($this->moznosti)->map(function ($moznostId, $zoznamKod) {
            $zoznam = $this->udalost->moznosti->filter(
                fn(ZoznamMoznostiUdalostiValueObject $zoznamMoznostiUdalostiValueObject,
                )
                    => $zoznamMoznostiUdalostiValueObject->getKod() === $zoznamKod,
            )->first();

            return new ZoznamZvolenychMoznostiUdalostiValueObject(
                $zoznam->getNazov(),
                $zoznam->getKod(),
                collect($zoznam->getMoznosti())->filter(
                    fn(MoznostUdalostiValueObject $moznostUdalostiValueObject) => $moznostUdalostiValueObject->getId(
                        ) === $moznostId,
                )->values()->all(),
            );
        })->values();
    }
}
