<?php
/**
 * Created by PhpStorm.
 * User: radko
 * Date: 15.11.18
 * Time: 11:23
 */

namespace Seka\Vzdelavanie\Services;

use Illuminate\Database\Eloquent\ModelNotFoundException as EloquentModelNotFoundException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Seka\Vzdelavanie\Enums\ModelStatusEnum;
use Seka\Vzdelavanie\Models\Kniznica\Kategoria;
use Seka\Vzdelavanie\Repositories\Contracts\KategoriaRepositoryInterface;
use Seka\Vzdelavanie\Repositories\Contracts\UcebnicaRepositoryInterface;
use Seka\Vzdelavanie\Repositories\Exceptions\ModelNotFoundException;
use Seka\Vzdelavanie\Repositories\Exceptions\ModelRelationshipsException;

/**
 * Class KategoriaService
 *
 * @package Seka\Vzdelavanie\Services
 */
class KategoriaService extends Service implements KategoriaServiceInterface
{
    /**
     * @var \Seka\Vzdelavanie\Repositories\Contracts\KategoriaRepositoryInterface
     */
    protected $kategoriaRepository;

    /**
     * @var \Seka\Vzdelavanie\Repositories\Contracts\UcebnicaRepositoryInterface
     */
    protected $ucebnicaRepository;

    /**
     * KategoriaService constructor.
     *
     * @param \Seka\Vzdelavanie\Repositories\Contracts\KategoriaRepositoryInterface $kategoriaRepository
     * @param \Seka\Vzdelavanie\Repositories\Contracts\UcebnicaRepositoryInterface  $ucebnicaRepository
     */
    public function __construct(
        KategoriaRepositoryInterface $kategoriaRepository,
        UcebnicaRepositoryInterface $ucebnicaRepository,
    ) {
        $this->kategoriaRepository = $kategoriaRepository;
        $this->ucebnicaRepository = $ucebnicaRepository;
    }

    /**
     * @param int $id
     *
     * @return mixed
     * @throws \Seka\Vzdelavanie\Repositories\Exceptions\ModelNotFoundException
     */
    public function vratPodlaId(int $id): mixed
    {
        try {
            return $this->kategoriaRepository->query()->findOrFail($id);
        } catch (EloquentModelNotFoundException) {
            throw new ModelNotFoundException();
        }
    }

    /**
     * @param int      $id
     * @param int|null $pocet
     *
     * @return \Seka\Vzdelavanie\Models\Kniznica\Kategoria
     * @throws \Seka\Vzdelavanie\Repositories\Exceptions\ModelNotFoundException
     */
    public function vratKategoriuSUcebnymiMaterialmi(int $id, int $pocet = null): Kategoria
    {
        try {
            /** @var \Seka\Vzdelavanie\Models\Kniznica\Kategoria $kategoria */
            $kategoria = $this->kategoriaRepository->query()->findOrFail($id);
            $ucebniceQuery = $this->ucebnicaRepository->query();

            // ak pouzivatel nema pravo na spravu vzdelavania, tak sa zobrazia len publikovane ucebne materialy
            if (false === Auth::user()->hasPermissionTo('vzdelavanie')) {
                $ucebniceQuery->where('stav', ModelStatusEnum::PUBLIKOVANE);
            }

            $ucebniceQuery
                ->where('kategoria_id', $kategoria->id)
                ->where('stav', ModelStatusEnum::PUBLIKOVANE)
                ->limit($pocet);

            $kategoria->ucebnice = $ucebniceQuery->get();

            return $kategoria;
        } catch (EloquentModelNotFoundException) {
            throw new ModelNotFoundException();
        }
    }

    /**
     * @return \Illuminate\Support\Collection
     */
    public function vratVsetky(): Collection
    {
        return $this->kategoriaRepository->query()->get();
    }

    /**
     * @param int $pocetUcebnychMaterialov
     *
     * @return \Illuminate\Support\Collection
     */
    public function vratVsetkySUcebnymiMaterialmi(int $pocetUcebnychMaterialov = 5): Collection
    {
        $publikovane = false;

        // ak pouzivatel nema pravo na spravu vzdelavania, tak sa zobrazia len publikovane ucebne materialy
        if (false === Auth::user()->hasPermissionTo('vzdelavanie')) {
            $publikovane = true;
        }

        return $this->kategoriaRepository
            ->query()
            ->allowedIncludes('ucebnice')
            ->withCount([
                'ucebnice as ucebnice_count' => function ($query) use ($publikovane) {
                    if ($publikovane) {
                        $query->where('stav', ModelStatusEnum::PUBLIKOVANE);
                    }
                },
            ])
            ->get()
            ->map(function ($query) use ($pocetUcebnychMaterialov, $publikovane) {
                if ($publikovane) {
                    $query->setRelation(
                        'ucebnice',
                        $query->ucebnice->where('stav', ModelStatusEnum::PUBLIKOVANE)->take($pocetUcebnychMaterialov),
                    );
                } else {
                    $query->setRelation('ucebnice', $query->ucebnice->take($pocetUcebnychMaterialov));
                }

                return $query;
            });
    }

    /**
     * @param array $udaje
     *
     * @return mixed
     */
    public function vytvorit(array $udaje): mixed
    {
        return $this->kategoriaRepository->create($udaje);
    }

    /**
     * @param int   $id
     * @param array $udaje
     *
     * @return mixed
     * @throws \Seka\Vzdelavanie\Repositories\Exceptions\ModelNotFoundException
     */
    public function upravit(int $id, array $udaje = []): mixed
    {
        return $this->kategoriaRepository->update($udaje, $id);
    }

    /**
     * @param int $id
     *
     * @throws \Seka\Vzdelavanie\Repositories\Exceptions\ModelRelationshipsException
     * @throws \Seka\Vzdelavanie\Repositories\Exceptions\ModelNotFoundException
     */
    public function odstranit(int $id): void
    {
        /** @var Kategoria $kategoria */
        $kategoria = $this->kategoriaRepository->query()->find($id);
        $ucebnicKategorie = $this->ucebnicaRepository->findBy('kategoria_id', $kategoria->id, ['id']);

        if (!is_null($ucebnicKategorie) && $ucebnicKategorie->count() > 0) {
            throw new ModelRelationshipsException(
                'Na kategóriu existujú previazané učebné materiály, nie je možné ju odstrániť.',
            );
        }

        $this->kategoriaRepository->delete($kategoria->id);
    }
}
