<?php

namespace App\Http\Livewire\Components\Informacia\Components;

use App\Enums\RolaPouzivatelaEnum;
use App\Models\Informacia\Enums\StavInformacieEnum;
use App\Models\Informacia\Informacia;
use Carbon\Carbon;
use Exception;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Rule;
use Illuminate\View\View;
use Livewire\Component;
use Livewire\Redirector;
use Throwable;

/**
 * Class Form
 *
 * @package App\Http\Livewire\Components\Informacia\Components
 */
final class Form extends Component
{
    use AuthorizesRequests;

    /**
     * @var Informacia|null
     */
    public ?Informacia $informacia;

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

    /**
     * @param Informacia|null $informacia
     * @return void
     */
    public function mount(?Informacia $informacia): void
    {
        $this->informacia = $informacia ?? new Informacia();

        if ($this->informacia->exists) {
            $this->selectedRoles = $this->informacia->zverejnit_pre_pouzivatelov_podla_role ?? [];
        }
    }

    /**
     * @return Application|Factory|View
     */
    public function render()
    {
        return view('pages.sprava.informacie.livewire.components.form');
    }

    /**
     * Vytvorit novu alebo aktualizovat existujucu informaciu
     *
     * @return Redirector|RedirectResponse
     * @throws Throwable
     */
    public function save()
    {
        $this->validate();

        try {
            $this->authorize('portal_sprava');

            $existBeforeSave = $this->informacia->exists ?? false;

            DB::beginTransaction();

            if (is_null($this->informacia->cas_zverejnenia) && $this->informacia->stav->equals(
                    StavInformacieEnum::ZVEREJNENA(),
                )) {
                $this->informacia->cas_zverejnenia = now();
            }

            $this->informacia->zverejnit_pre_pouzivatelov_podla_role = $this->selectedRoles;

            $this->informacia->vytvoril()->associate(auth()->user());
            $this->informacia->save();
            $this->informacia->refresh();

            DB::commit();

            $message = $existBeforeSave ? 'Informácia bola aktualizovaná' : 'Nová informácia bola vytvorená';

            flash()->overlay($message, 'Hlásenie')->success();
        } catch (Exception $e) {
            DB::rollBack();

            Log::error($e->getMessage(), $e->getTrace());

            flash()->overlay('Informácia nebola úspešne uložená.', 'Hlásenie')->error();
        }

        return redirect()->route('portal.sprava.informacie.index');
    }

    /**
     * @return Redirector|RedirectResponse
     */
    public function cancel()
    {
        return redirect()->route('portal.sprava.informacie.index');
    }

    /**
     * Zneplatnit informaciu
     *
     * @return Redirector|RedirectResponse
     */
    public function trash()
    {
        try {
            $this->authorize('portal_sprava');

            DB::beginTransaction();

            // soft delete
            $this->informacia->delete();

            DB::commit();

            flash()->overlay('Informácia bola úspešne zneplatnená', 'Hlásenie')->success();
        } catch (Exception $e) {
            DB::rollBack();

            Log::error($e->getMessage(), $e->getTrace());

            flash()->overlay('Informácia nebola zneplatnená.', 'Hlásenie')->error();
        } finally {
            return redirect()->route('portal.sprava.informacie.index');
        }
    }

    /**
     * Obnovit zneplatnenu informaciu
     *
     * @return Redirector|RedirectResponse
     */
    public function restore()
    {
        try {
            $this->authorize('portal_sprava');

            if (!$this->informacia->trashed()) {
                throw new Exception('Informácia nemohla byť obnovená, pretože nie je zneplatnená.');
            }

            DB::beginTransaction();

            $this->informacia->restore();

            DB::commit();

            $this->informacia->refresh();

            flash()->overlay('Informácia bola úspešne obnovená', 'Hlásenie')->success();
        } catch (Exception $e) {
            DB::rollBack();

            Log::error($e->getMessage(), $e->getTrace());

            flash()->overlay('Informáciu sa nepodarilo obnoviť.', 'Hlásenie')->error();
        } finally {
            return redirect()->route('portal.sprava.informacie.index');
        }
    }

    /**
     * @param $value
     * @param $attribute
     * @return void
     */
    public function updatedInformacia($value, $attribute): void
    {
        switch ($attribute) {
            case 'stav':
                $this->informacia->stav = StavInformacieEnum::from($value);
                break;
            case 'odporucane':
                $this->informacia->odporucane = (bool)$value;
                break;
            case 'planovany_cas_zverejnenia':
                $this->informacia->planovany_cas_zverejnenia = Carbon::make($value)->setTimezone(
                    config('app.timezone'),
                );
                break;
        }
    }

    /**
     * @param $value
     * @return void
     */
    public function updatedSelectedRoles($value): void
    {
        $this->informacia->zverejnit_pre_pouzivatelov_podla_role = $value;
    }

    /**
     * Ak informacia existuje, tak formular je v rezime uprava
     *
     * @return bool
     */
    public function editMode(): bool
    {
        return $this->informacia->exists;
    }

    /**
     * Ak je informacia zneplatnena, tak formular je v rezime zneplatnenia
     *
     * @return bool
     */
    public function trashMode(): bool
    {
        return $this->informacia->trashed();
    }

    /**
     * @return string[]
     */
    public function rules(): array
    {
        return [
            'informacia.titulok' => 'required',
            'informacia.uvod' => 'required',
            'informacia.obsah' => 'required',
            'informacia.stav' => [
                'required',
                Rule::in(StavInformacieEnum::toValues()),
            ],
            'selectedRoles' => [
                'array',
                Rule::in(RolaPouzivatelaEnum::toValues()),
            ],
            'informacia.planovany_cas_zverejnenia' => [
                'exclude_unless:informacia.stav,' . StavInformacieEnum::PLANOVANE_ZVEREJNENIE()->value,
                'required',
                'date',
            ],
            'informacia.odoslat_email_na_pek' => 'required|boolean',
            'informacia.odoslat_email_pouzivatelom' => 'required|boolean',
            'informacia.odoslat_push_notifikacie_pouzivatelom' => 'required|boolean',
            'informacia.odporucane' => 'required|boolean',
        ];
    }

    /**
     * @return string[]
     */
    public function messages(): array
    {
        return [
            'informacia.titulok.required' => 'Titulok informácie je vyžadovaný',
            'informacia.uvod.required' => 'Úvod informácie je vyžadovaný',
            'informacia.obsah.required' => 'Obsah informácie je vyžadovaný',
            'informacia.stav.required' => 'Stav informácie je vyžadovaný',
            'informacia.stav.in' => 'Neznámi stav informácie',
            'selectedRoles.array' => 'Zoznam rolí musí byť pole',
            'selectedRoles.*.in' => 'Neplatná hodnota role',
            'informacia.planovany_cas_zverejnenia.required' => 'Pri plánovanom zverejnení je potrebné zadať plánovaný čas zverejnenia',
            'informacia.planovany_cas_zverejnenia.date' => 'Plánovaný čas zverejnenia musí byť vo formáte dátumu a času',
            'informacia.odoslat_email_na_pek.required' => 'vyžadované',
            'informacia.odoslat_email_na_pek.boolean' => 'Hodnota musí byť boolean',
            'informacia.odoslat_email_pouzivatelom.required' => 'vyžadované',
            'informacia.odoslat_email_pouzivatelom.boolean' => 'Hodnota musí byť boolean',
            'informacia.odoslat_push_notifikacie_pouzivatelom.required' => 'vyžadované',
            'informacia.odoslat_push_notifikacie_pouzivatelom.boolean' => 'Hodnota musí byť boolean',
            'informacia.odporucane.required' => 'vyžadované',
            'informacia.odporucane.boolean' => 'Hodnota musí byť boolean',
        ];
    }
}
