<?php

declare(strict_types=1);

namespace Seka\Terminy\Http\Controllers\Backend\Adresar\Livewire\Components;

use Exception;
use Livewire\Component;
use Geocoder\Model\Address;
use Illuminate\Support\Facades\DB;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Log;
use Geocoder\Laravel\Facades\Geocoder;
use Seka\Terminy\Models\MiestoKonania\MiestoKonania;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

/**
 * Class Form
 *
 * @package Seka\Terminy\Http\Controllers\Backend\Adresar\Livewire\Components
 */
final class Form extends Component
{
    use AuthorizesRequests;

    /**
     * @var \Seka\Terminy\Models\MiestoKonania\MiestoKonania
     */
    public MiestoKonania $miesto;

    /**
     * @var string[]
     */
    protected $listeners = [
        'geocoding',
    ];

    /**
     * @param \Seka\Terminy\Models\MiestoKonania\MiestoKonania $miesto
     */
    public function mount(MiestoKonania $miesto): void
    {
        $this->miesto = $miesto;
    }

    /**
     * @return \Illuminate\Contracts\View\View
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function render(): View
    {
        return view('Terminy::pages.adresar.backend.livewire.components.form');
    }

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

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

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

            DB::beginTransaction();

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

            DB::commit();

            if (false == $existBeforeSave) {
                $message = 'Nové miesto bolo vytvorené';
            } else {
                $message = 'Miesto bolo aktualizované';
            }

            flash()->overlay($message, 'Hlásenie')->success();

            return redirect()->route('modul.terminy.backend.adresar.index');
        } catch (Exception $e) {
            DB::rollBack();

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

            flash()->overlay('Miesto nebolo úspešne uložené.')->error();
        }
    }

    /**
     * Obnovit zneplatnene miesto
     *
     * @return void
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function restore(): void
    {
        try {
            $this->authorize('terminy');

            if (!$this->miesto->trashed()) return;

            DB::beginTransaction();

            $this->miesto->restore();

            DB::commit();

            $this->miesto->refresh();

            flash()->overlay('Miesto bolo úspešne obnovené')->success();
        } catch (Exception $e) {
            DB::rollBack();

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

            flash()->overlay('Miesto sa nepodarilo obnoviť.')->error();
        }
    }

    /**
     * Zneplatnit miesto
     *
     * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function trash()
    {
        try {
            $this->authorize('terminy');

            DB::beginTransaction();

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

            DB::commit();

            flash()->overlay('Miesto bolo úspešne zneplatnené')->success();

            return redirect()->route('modul.terminy.backend.adresar.index');
        } catch (Exception $e) {
            DB::rollBack();

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

            flash()->overlay('Miesto nebolo zneplatnené.')->error();
        }
    }

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

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

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

    /**
     * @param float $lat
     * @param float $long
     */
    public function geocoding(float $lat, float $long): void
    {
        $result = Geocoder::reverse($lat, $long)->get()->first();

        if ($result instanceof Address) {
            /** @var $result Address */
            $this->miesto->setAttribute('ulica',  sprintf('%s %s', $result->getStreetName(), $result->getStreetNumber()));
            $this->miesto->setAttribute('obec',  $result->getLocality());
            $this->miesto->setAttribute('psc',  $result->getPostalCode() ? trim($result->getPostalCode()) : '');
            $this->miesto->setAttribute('krajina',  $result->getCountry()->getName() ? trim($result->getCountry()->getName()) : '');
            $this->miesto->setAttribute('latitude',  $result->getCoordinates()->getLatitude());
            $this->miesto->setAttribute('longitude',  $result->getCoordinates()->getLongitude());
        }
    }

    /**
     * @return string[]
     */
    public function rules(): array
    {
        return [
            'miesto.nazov' => 'required',
            'miesto.ulica' => 'required',
            'miesto.obec' => 'required',
            'miesto.psc' => 'required|numeric',
            'miesto.krajina' => 'required',
            'miesto.latitude' => 'required|numeric|regex:/^-?\d{1,2}.\d{0,16}$/',
            'miesto.longitude' => 'required|numeric|regex:/^-?\d{1,3}.\d{0,16}$/',
        ];
    }

    /**
     * @return string[]
     */
    public function messages(): array
    {
        return [
            'miesto.nazov.required' => 'Názov miesta je vyžadovaný',
            'miesto.ulica.required' => 'Ulica je vyžadovaná',
            'miesto.obec.required' => 'Obec je vyžadovaná',
            'miesto.psc.required' => 'PSČ je vyžadované',
            'miesto.psc.numeric' => 'PSČ je vyžadované vo formáte čísla',
            'miesto.krajina.required' => 'Krajina je vyžadovaná',
            'miesto.latitude.required' => 'Zemepisná šírka je vyžadovaná',
            'miesto.latitude.numeric' => 'Zemepisná šírka je vyžadovaná vo formáte čísla',
            'miesto.latitude.regex' => 'Zemepisná šírka je vyžadovaná vo formáte čísla s desatinnou bodkou',
            'miesto.longitude.required' => 'Zemepisná dĺžka je vyžadovaná',
            'miesto.longitude.numeric' => 'Zemepisná dĺžka je vyžadovaná vo formáte čísla',
            'miesto.longitude.regex' => 'Zemepisná dĺžka je vyžadovaná vo formáte čísla s desatinnou bodkou',
        ];
    }
}
