<?php
/**
 * Created by PhpStorm.
 * User: radko
 * Date: 12.11.18
 * Time: 15:33
 */

namespace Seka\Portal\Modul\Vzdelavanie\Providers;

use ConsoleTVs\Charts\Registrar;
use Illuminate\Contracts\Foundation\CachesConfiguration;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\ServiceProvider;
use Livewire\Livewire;
use Seka\Portal\Modul\Vzdelavanie\Charts\UspesnostRieseniaTestovNaPekChart;
use Seka\Portal\Modul\Vzdelavanie\Commands\Console\ImportTestov;
use Seka\Portal\Modul\Vzdelavanie\Commands\Console\SpracovanieNevyhodnotenychTestov;
use Seka\Portal\Modul\Vzdelavanie\Composers\Kniznica\ZoznamKategoriiComposer;
use Seka\Portal\Modul\Vzdelavanie\Composers\Kniznica\ZoznamOblubenychPoloziekPouzivatelaComposer;
use Seka\Portal\Modul\Vzdelavanie\Composers\Kniznica\ZoznamUcebnychMaterialovPodlaKategoriiComposer;
use Seka\Portal\Modul\Vzdelavanie\Composers\Testovanie\ZoznamTestovPodlaPopularnostiCompose;
use Seka\Portal\Modul\Vzdelavanie\Livewire\Components\Pracoviska;
use Seka\Portal\Modul\Vzdelavanie\Livewire\Components\SearchText;
use Seka\Portal\Modul\Vzdelavanie\Livewire\Components\Stav;
use Seka\Portal\Modul\Vzdelavanie\Livewire\Sprava\Testovanie\Pouzivatelia\Components\Zoznam;
use Seka\Portal\Modul\Vzdelavanie\Models\Kniznica\Sekcia;
use Seka\Portal\Modul\Vzdelavanie\Models\Kniznica\Ucebnica;
use Seka\Portal\Modul\Vzdelavanie\Models\Testovanie\Test;
use Seka\Portal\Modul\Vzdelavanie\Repositories\Contracts\KategoriaRepositoryInterface;
use Seka\Portal\Modul\Vzdelavanie\Repositories\Contracts\SekciaRepositoryInterface;
use Seka\Portal\Modul\Vzdelavanie\Repositories\Contracts\UcebnicaRepositoryInterface;
use Seka\Portal\Modul\Vzdelavanie\Repositories\Eloquent\KategoriaRepository;
use Seka\Portal\Modul\Vzdelavanie\Repositories\Eloquent\SekciaRepository;
use Seka\Portal\Modul\Vzdelavanie\Repositories\Eloquent\UcebnicaRepository;
use Seka\Portal\Modul\Vzdelavanie\Services\KategoriaService;
use Seka\Portal\Modul\Vzdelavanie\Services\KategoriaServiceInterface;
use Seka\Portal\Modul\Vzdelavanie\Services\SekciaService;
use Seka\Portal\Modul\Vzdelavanie\Services\SekciaServiceInterface;
use Seka\Portal\Modul\Vzdelavanie\Services\UcebnicaService;
use Seka\Portal\Modul\Vzdelavanie\Services\UcebnicaServiceInterface;
use Seka\Portal\Modul\Vzdelavanie\VzdelavanieRolesPermissions;

/**
 * Class VzdelavanieServiceProvider
 *
 * @package Seka\Portal\Modul\Vzdelavanie\Providers
 */
class VzdelavanieServiceProvider extends ServiceProvider
{
    /**
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function boot(): void
    {
        $this->app->bind(VzdelavanieRolesPermissions::class, function () {
            return new VzdelavanieRolesPermissions();
        });

        $this->app->tag([
            VzdelavanieRolesPermissions::class,
        ], 'roleaopravnenia');

        $this->app->booted(function () {
            $this->breadcrumbs();

            Relation::morphMap([
                Test::type() => Test::class,
                Sekcia::type() => Sekcia::class,
                Ucebnica::type() => Ucebnica::class,
            ]);
        });

        if ($this->app->runningInConsole()) {
            $this->commands([
                ImportTestov::class,
                SpracovanieNevyhodnotenychTestov::class,
            ]);
        }

        $this->app->get(Registrar::class)->register([
            UspesnostRieseniaTestovNaPekChart::class,
        ]);

        $this->publishConfig();
        $this->publishViews();
        $this->publishAssets();
        $this->loadViewsFrom(__DIR__ . '/../../resources/views', 'Vzdelavanie');

        $this->loadLivewireComponents();
    }

    protected function breadcrumbs(): void
    {
        if (class_exists('Breadcrumbs')) {
            // BACKEND
            require __DIR__ . '/../../routes/backend/breadcrumbs.php';
            require __DIR__ . '/../../routes/backend/testy/breadcrumbs.php';
            require __DIR__ . '/../../routes/backend/kniznica/breadcrumbs.php';

            // FRONTEND
            require __DIR__ . '/../../routes/frontend/breadcrumbs.php';
            require __DIR__ . '/../../routes/frontend/testy/breadcrumbs.php';
            require __DIR__ . '/../../routes/frontend/kniznica/breadcrumbs.php';
        }
    }

    /**
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function register(): void
    {
        $this->registerRepositoryBindings();
        $this->registerServiceBindings();
        $this->registerConfig();
        $this->registerComposers();
        $this->registerEvents();
        $this->registerAuths();
        $this->registerRoutes();
        $this->registersCommands();
    }

    protected function registerRepositoryBindings(): void
    {
        $this->app->bind(
            KategoriaRepositoryInterface::class,
            KategoriaRepository::class,
        );
        $this->app->bind(
            UcebnicaRepositoryInterface::class,
            UcebnicaRepository::class,
        );
        $this->app->bind(
            SekciaRepositoryInterface::class,
            SekciaRepository::class,
        );
    }

    protected function registerServiceBindings(): void
    {
        $this->app->bind(
            KategoriaServiceInterface::class,
            KategoriaService::class,
        );
        $this->app->bind(
            UcebnicaServiceInterface::class,
            UcebnicaService::class,
        );
        $this->app->bind(
            SekciaServiceInterface::class,
            SekciaService::class,
        );
    }

    /**
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    protected function registerConfig(): void
    {
        $this->mergeConfigFrom(__DIR__ . '/../../config/vzdelavanie.php', 'vzdelavanie');
        $this->mergeConfigFrom(__DIR__ . '/../../config/charts.php', 'charts');
        $this->mergeConfigFrom(__DIR__ . '/../../config/lfm.php', 'lfm');
    }

    /**
     * Prepisuje hodnoty klucov existujucej konfiguracie
     * Povodna metoda neprepisuje hodnoty klucov existujucu konfiguracie, len ju doplna v pripade absencie klucov,
     * reps. ich hodnot
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    protected function mergeConfigFrom($path, $key): void
    {
        if (!($this->app instanceof CachesConfiguration && $this->app->configurationIsCached())) {
            $config = $this->app->make('config');

            $config->set(
                $key,
                array_merge(
                    $config->get($key, []),
                    require $path,
                ),
            );
        }
    }

    /**
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function registerComposers(): void
    {
        // frontend
        view()->composer(
            ['Vzdelavanie::pages.kniznica.index'],
            ZoznamKategoriiComposer::class,
        );
        view()->composer(
            ['Vzdelavanie::pages.kniznica.index'],
            ZoznamUcebnychMaterialovPodlaKategoriiComposer::class,
        );
        view()->composer(
            ['Vzdelavanie::pages.testovanie.index'],
            ZoznamTestovPodlaPopularnostiCompose::class,
        );
        view()->composer(
            ['Vzdelavanie::pages.kniznica.index'],
            ZoznamOblubenychPoloziekPouzivatelaComposer::class,
        );

        // backend
        view()->composer(
            ['Vzdelavanie::pages.sprava.kniznica.index'],
            ZoznamKategoriiComposer::class,
        );
        view()->composer(
            ['Vzdelavanie::pages.sprava.kniznica.index'],
            ZoznamOblubenychPoloziekPouzivatelaComposer::class,
        );
    }

    public function registerEvents(): void
    {
        $this->app->register(EventServiceProvider::class);
    }

    public function registerAuths(): void
    {
        $this->app->register(AuthServiceProvider::class);
    }

    public function registerRoutes(): void
    {
        $this->app->register(RouteServiceProvider::class);
    }

    private function registersCommands(): void
    {
        $this->commands([
            SpracovanieNevyhodnotenychTestov::class,
        ]);
    }

    private function publishConfig(): void
    {
        if ($this->app->runningInConsole()) {
            $this->publishes([
                __DIR__ . '/../../config/vzdelavanie.php' => config_path('vzdelavanie.php'),
            ], 'config');
        }
    }

    private function publishViews(): void
    {
        $this->publishes([
            __DIR__ . '/../../resources/views' => resource_path('views/vendor/seka/vzdelavanie'),
        ], 'views');
    }

    private function publishAssets(): void
    {
        $this->publishes([
            __DIR__ . '/../../public/assets' => public_path('vendor/seka/vzdelavanie'),
        ], 'assets');
    }

    private function loadLivewireComponents(): void
    {
        Livewire::component('Vzdelavanie.components.stav', Stav::class);
        Livewire::component('Vzdelavanie.components.pracoviska', Pracoviska::class);
        Livewire::component('Vzdelavanie.components.search-text', SearchText::class);
        Livewire::component('Vzdelavanie.sprava.testovanie.pouzivatelia.components.zoznam', Zoznam::class);
    }
}
