<?php

declare(strict_types=1);

namespace Seka\Portal\Modul\Terminy\Livewire\Backend\MoznostiUdalosti\Components;

use Exception;
use Illuminate\Contracts\View\View;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Rule;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Validate;
use Livewire\Component;
use Seka\Portal\Modul\Terminy\Entities\MoznostiUdalosti\MoznostUdalosti;
use Seka\Portal\Modul\Terminy\Entities\MoznostiUdalosti\StavMoznostiUdalostiEnum;

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

    #[Locked]
    public ?int $id = null;
    #[Validate]
    public ?string $nazov = null;
    public ?string $kod = null;
    #[Validate]
    public ?StavMoznostiUdalostiEnum $stav = StavMoznostiUdalostiEnum::ZVEREJNENA;
    public bool $exists = false;
    public bool $trashed = false;

    public function mount(?MoznostUdalosti $moznostUdalosti = null): void
    {
        if (!$moznostUdalosti) {
            return;
        }

        $this->fillForm($moznostUdalosti);
    }

    /**
     * @param \Seka\Portal\Modul\Terminy\Entities\MoznostiUdalosti\MoznostUdalosti $moznostUdalosti
     *
     * @return void
     */
    public function fillForm(MoznostUdalosti $moznostUdalosti): void
    {
        $this->fill($moznostUdalosti?->only('id', 'nazov', 'kod', 'stav'));
        $this->exists = $moznostUdalosti?->exists;
        $this->trashed = $moznostUdalosti?->trashed();
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    public function render(): View
    {
        return view('Terminy::livewire.backend.moznosti-udalosti.components.form');
    }

    /**
     * @throws \Illuminate\Validation\ValidationException
     * @throws \Throwable
     */
    public function save()
    {
        $this->validate();

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

            DB::beginTransaction();

            $moznostUdalosti = new MoznostUdalosti();

            if ($this->exists) {
                $moznostUdalosti = MoznostUdalosti::query()->findOrFail($this->id);
            }

            $moznostUdalosti->fill($this->except('id'));
            $moznostUdalosti->vytvoril()->associate(auth()->user());
            $moznostUdalosti->save();

            DB::commit();

            if ($this->exists) {
                $message = 'Možnosť udalosti bola aktualizovaná';
            } else {
                $message = 'Nová možnosť udalosti bola vytvorená';
            }

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

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

            flash()->error('Možnosť udalosti nebola úspešne uložená.');
        } finally {
            return redirect()->route('modul.terminy.backend.moznostiUdalosti.index');
        }
    }

    /**
     * Obnovit zneplatnenú možnosť udalosti
     *
     * @throws \Throwable
     */
    public function restore(): void
    {
        try {
            $this->authorize('terminy');

            if (!$this->trashed || !$this->exists) {
                return;
            }

            DB::beginTransaction();

            MoznostUdalosti::onlyTrashed()->findOrFail($this->id)->restore();

            DB::commit();

            flash()->success('Možnosť udalosti bola úspešne obnovená');
        } catch (Exception $e) {
            DB::rollBack();

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

            flash()->error('Možnosť udalosti sa nepodarilo obnoviť.');
        } finally {
            $this->fillForm(MoznostUdalosti::withTrashed()->findOrFail($this->id));
        }
    }

    /**
     * Zneplatnit možnosť udalosti
     *
     * @throws \Throwable
     */
    public function trash(): void
    {
        try {
            $this->authorize('terminy');

            DB::beginTransaction();

            if ($this->trashed || !$this->exists) {
                return;
            }

            // soft delete
            MoznostUdalosti::query()->findOrFail($this->id)->delete();

            DB::commit();

            flash()->success('Možnosť udalosti bola úspešne zneplatnená');
        } catch (Exception $e) {
            DB::rollBack();

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

            flash()->error('Možnosť udalosti nebola zneplatnená.');
        } finally {
            $this->fillForm(MoznostUdalosti::withTrashed()->findOrFail($this->id));
        }
    }

    /**
     * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function cancel()
    {
        return redirect()->route('modul.terminy.backend.moznostiUdalosti.index');
    }

    /**
     * @return string[]
     */
    public function rules(): array
    {
        return [
            'nazov' => 'required|min:5|max:128',
            'stav' => [
                'required',
                Rule::enum(StavMoznostiUdalostiEnum::class),
            ],
        ];
    }

    /**
     * @return string[]
     */
    public function messages(): array
    {
        return [
            'nazov.required' => 'Názov možnosti udalosti je vyžadovaný',
            'nazov.min' => 'Názov by mal obsahovať aspoň :min znakov',
            'nazov.max' => 'Názov smie obsahovať maximálne :max znakov',
            'stav.required' => 'Stav možnosti udalosti je vyžadovaný',
            'stav.enum' => 'Neznámi stav možnosti udalosti',
        ];
    }
}
