<?php

namespace App\Livewire\Backend\Informacie;

use App\Enums\RolaPouzivatelaEnum;
use App\Models\Informacia\Enums\StavInformacieEnum;
use App\Models\Informacia\Informacia;
use Carbon\Carbon;
use Exception;
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\Features\SupportRedirects\Redirector;
use Throwable;

/**
 * Class Form
 */
final class Form extends Component
{
    use AuthorizesRequests;

    public ?Informacia $informacia;

    public ?string $titulok;
    public ?string $uvod;
    public ?string $obsah;
    public StavInformacieEnum $stav = StavInformacieEnum::ROZPISANA;
    public ?string $planovany_cas_zverejnenia = null;
    public ?bool $odoslat_email_na_pek = false;
    public ?bool $odoslat_email_pouzivatelom = false;
    public ?bool $odoslat_push_notifikacie_pouzivatelom = false;
    public ?bool $odporucane = false;

    public array $selectedRoles = [];

    public function mount(?Informacia $informacia): void
    {
        $this->informacia = $informacia ?? new Informacia;

        $this->fill(
            $informacia->only(
                'titulok',
                'uvod',
                'obsah',
                'stav',
                'planovany_cas_zverejnenia',
                'odoslat_email_na_pek',
                'odoslat_email_pouzivatelom',
                'odoslat_push_notifikacie_pouzivatelom',
                'odporucane',
            ),
        );

        $this->selectedRoles = $informacia->zverejnit_pre_pouzivatelov_podla_role?->pluck(
            'name',
        )->toArray() ?? [];
    }

    public function render(): View
    {
        return view('livewire.backend.informacie.form');
    }

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

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

            $existBeforeSave = $this->informacia->exists ?? false;
            $this->informacia->fill([
                'titulok' => $this->titulok,
                'uvod' => $this->uvod,
                'obsah' => $this->obsah,
                'stav' => $this->stav,
                'zverejnit_pre_pouzivatelov_podla_role' => $this->selectedRoles,
                'planovany_cas_zverejnenia' => $this->planovany_cas_zverejnenia,
                'odoslat_email_na_pek' => $this->odoslat_email_na_pek,
                'odoslat_email_pouzivatelom' => $this->odoslat_email_pouzivatelom,
                'odoslat_push_notifikacie_pouzivatelom' => $this->odoslat_push_notifikacie_pouzivatelom,
                'odporucane' => $this->odporucane,
            ]);

            DB::beginTransaction();

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

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

            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');
    }

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

    /**
     * Zneplatnit informaciu
     *
     * @throws \Throwable
     */
    public function trash(): Redirector|RedirectResponse
    {
        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
     *
     * @throws \Throwable
     */
    public function restore(): Redirector|RedirectResponse
    {
        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();
        }
    }

    public function updatedStav($value): void
    {
        $this->informacia->stav = $value;
    }

    public function updatedPlanovanyCasZverejnenia($value): void
    {
        $this->informacia->planovany_cas_zverejnenia = Carbon::createFromFormat('Y-m-d\\TH:i', $value);
    }

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

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

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

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