<?php

declare(strict_types=1);

namespace App\Services\PushNotificationsService;

use App\Dtos\PouzivatelDto;
use App\Models\Pouzivatel\Pouzivatel;
use App\Notifications\Push\MAAISEKUserActivatedPushNotification;
use App\Notifications\Push\MAAISEKUserNotificationsCountPushNotification;
use App\Repositories\PouzivatelRepositoryContract;
use Exception;
use Illuminate\Support\Facades\Log;
use Kreait\Firebase\Exception\Messaging\AuthenticationError;
use Kreait\Firebase\Exception\Messaging\InvalidMessage;
use Kreait\Firebase\Exception\Messaging\NotFound;
use Kreait\Firebase\Messaging;
use Kreait\Firebase\Messaging\Topic;
use Seka\Portal\Core\Notifications\Enums\NotificationTopicEnum;
use Spatie\Permission\Models\Role;

/**
 * Class FCMPushNotificationsService
 *
 * @package App\Services\PushNotificationsService
 */
final class FCMPushNotificationsService implements PushNotificationsServiceContract
{
    /**
     * @var \App\Repositories\PouzivatelRepositoryContract
     */
    private PouzivatelRepositoryContract $pouzivatelRepository;

    /**
     * @var \Kreait\Firebase\Messaging|\Kreait\Firebase\Contract\Messaging
     */
    private Messaging $messaging;

    /**
     * @param \App\Repositories\PouzivatelRepositoryContract $pouzivatelRepository
     */
    public function __construct(PouzivatelRepositoryContract $pouzivatelRepository)
    {
        $this->pouzivatelRepository = $pouzivatelRepository;
        $this->messaging = app('firebase.messaging');
    }

    /**
     * @param \App\Models\Pouzivatel\Pouzivatel $pouzivatel
     * @param string                            $token
     *
     * @return void
     */
    public function userDeviceTokenStored(Pouzivatel $pouzivatel, string $token): void
    {
        $pouzivatel = $this->pouzivatelRepository->saveNotificationToken($pouzivatel->getKey(), $token);
        $pouzivatelDto = PouzivatelDto::from($pouzivatel->toArray());

        // odosle push notifikaciu pouzivatelovi s informaciou o aktivovani push notifikacii na danom zariadeni
        $pouzivatel->notify(new MAAISEKUserActivatedPushNotification($pouzivatelDto));
        // odosle push notifikaciu pouzivatelovi s poctom neprecitanych notifikacii
        $pouzivatel->notify(new MAAISEKUserNotificationsCountPushNotification);
    }

    /**
     * @param \App\Models\Pouzivatel\Pouzivatel $pouzivatel
     *
     * @return void
     */
    public function registerUserToTopics(Pouzivatel $pouzivatel): void
    {
        try {
            $roles = Role::all();

            $roles->each(function ($role) use ($pouzivatel) {
                /** @var \Spatie\Permission\Models\Role $role */
                switch ($role->name) {
                    case 'admin':
                        $this->messaging->subscribeToTopic(
                            Topic::fromValue(NotificationTopicEnum::pts_adm_denny_prehlad_vykonu_ek()->value),
                            $pouzivatel->notification_token,
                        );
                        break;
                    case 'technicka_podpora_pts':
                        $this->messaging->subscribeToTopic(
                            Topic::fromValue(NotificationTopicEnum::pts_tp_zadana_ziadost_o_specificky_postup()->value),
                            $pouzivatel->notification_token,
                        );
                        break;
                    case 'technik':
                        $this->messaging->subscribeToTopic(
                            Topic::fromValue(NotificationTopicEnum::pek_tek_informacia()->value),
                            $pouzivatel->notification_token,
                        );
                        break;
                    case 'spravca_pek':
                        $this->messaging->subscribeToTopic(
                            Topic::fromValue(NotificationTopicEnum::pek_spr_informacia()->value),
                            $pouzivatel->notification_token,
                        );
                        break;
                    case 'pek_konatel':
                        $this->messaging->subscribeToTopic(
                            Topic::fromValue(NotificationTopicEnum::pek_kon_informacia()->value),
                            $pouzivatel->notification_token,
                        );
                        break;
                    case 'pek_poverena_osoba':
                        $this->messaging->subscribeToTopic(
                            Topic::fromValue(NotificationTopicEnum::pek_poso_informacia()->value),
                            $pouzivatel->notification_token,
                        );
                        break;
                    case 'kalibrator':
                        $this->messaging->subscribeToTopic(
                            Topic::fromValue(NotificationTopicEnum::kali_informacia()->value),
                            $pouzivatel->notification_token,
                        );
                        break;
                }
            });
        } catch (Exception $exc) {
            Log::error(sprintf('portal:%s:%s:%s', __CLASS__, __METHOD__, $exc->getMessage()), $exc->getTrace());
        }
    }

    /**
     * @throws \Kreait\Firebase\Exception\FirebaseException
     * @throws \Kreait\Firebase\Exception\MessagingException
     */
    public function validateUsersTokens(array $tokens): array
    {
        $invalidTokens = [];

        foreach ($tokens as $token) {
            try {
                $this->messaging->send(['token' => $token], true);
            } catch (AuthenticationError|InvalidMessage|NotFound $exc) {
                $invalidTokens[] = $token;
            }
        }

        return $invalidTokens;
    }
}
