<?php

namespace YooMoney\Helpers\OauthHelpers;

use JUri;
use Psr\Log\LoggerInterface;
use YooKassa\Client;
use YooKassa\Model\NotificationEventType;
use YooKassa\Model\Webhook\Webhook;
use YooMoney\Helpers\JVersionDependenciesHelper;
use YooMoney\Helpers\YookassaClientFactory;

class OauthWebhooksHelper implements OauthWebhooksHelperInterface
{
    /** @var LoggerInterface */
    private $logger;

    /** @var YookassaClientFactory */
    private $clientFactory;

    /** @var Client */
    private $client;

    /** @var array */
    private $webhooks;

    /** @var JVersionDependenciesHelper */
    private $versionHelper;

    public function __construct(
        LoggerInterface $logger,
        YookassaClientFactory $clientFactory,
        JVersionDependenciesHelper $versionHelper
    )
    {
        $this->logger = $logger;
        $this->clientFactory = $clientFactory;
        $this->versionHelper = $versionHelper;
    }

    /**
     * Создание вебхуков по токену
     *
     * @param string $token
     * @param string $notificationUrl
     * @return void
     * @throws \Exception
     */
    public function addWebhooksWithGivenToken($token, $notificationUrl)
    {
        $this->client = $this->clientFactory->getClientWithGivenToken($token);
        $this->logger->log('info', 'Going to create webhooks for token: ' . $token);
        $this->addWebhooksWithSetClient($notificationUrl);
    }

    /**
     * Удаление вебхуков по токену
     *
     * @param string $token
     * @return void
     * @throws \Exception
     */
    public function removeWebhooksWithGivenToken($token)
    {
        $this->client = $this->clientFactory->getClientWithGivenToken($token);
        $this->logger->log('info', 'Going to remove webhooks for token: ' . $token);
        $this->removeWebhooksWithSetClient();
    }

    /**
     * Изменение url для вебхуков путем удаления, а потом создания новых вебхуков
     *
     * @param $notificationUrl
     * @return void
     * @throws \Exception
     */
    public function replaceWebhooksWithNewUrl($notificationUrl)
    {
        $this->client = $this->clientFactory->getClient();
        $this->removeWebhooksWithSetClient();
        $this->addWebhooksWithSetClient($notificationUrl);
    }

    /**
     * @param string $notificationUrl
     * @return void
     * @throws \Exception
     */
    private function addWebhooksWithSetClient($notificationUrl)
    {
        $webHookUrl = str_replace(
            'http://',
            'https://',
            $notificationUrl
        );

        foreach ($this->getNotificationEventList() as $event) {
            try {
                $this->client->addWebhook(array('event' => $event, 'url' => $webHookUrl));
                $this->logger->log('info', 'Webhook created: ' . $event . ':' . $webHookUrl);
            } catch (\Exception $e) {
                $this->logger->log('error', 'Webhook creation failed: ' . $event . ':' . $webHookUrl);
                throw $e;
            }
        }
    }

    /**
     * @return void
     * @throws \Exception
     */
    public function removeWebhooksWithSetClient()
    {
        $currentWebHookList = $this->client->getWebhooks()->getItems();

        if (!$currentWebHookList) {
            $this->logger->log('info', 'Webhooks not found');
            return;
        }

        foreach ($currentWebHookList as $webHook) {
            try {
                $this->client->removeWebhook($webHook->getId());
                $this->logger->log('info', 'Webhook was removed: ' . $webHook->getId());
            } catch (\Exception $e) {
                $this->logger->log('error', 'Failed remove webhook: ' . $webHook->getId());
                throw $e;
            }
        }

    }

    /**
     * Проверка на наличие вебхуков и их типов
     *
     * @return bool
     * @throws \Exception
     */
    public function checkWebhooks()
    {
        $currentWebHookList = $this->getCurrentWebhooks();

        if (empty($currentWebHookList)) {
            $this->logger->log('error', 'Webhooks not found');
            return false;
        }

        $countWebhook = 0;
        $webhookEvents = array();
        foreach ($currentWebHookList as $webHook) {
            if (
                in_array($webHook->getEvent(), $this->getNotificationEventList())
                && !in_array($webHook->getEvent(), $webhookEvents)
            ) {
                $countWebhook++;
                $webhookEvents[] = $webHook->getEvent();
            }
        }

        if ($countWebhook != 4) {
            $this->logger->log('error', 'Webhooks count less then 4');
            return false;
        }

        return true;
    }

    /**
     * Получение списка установленных вебхуков
     *
     * @return array|Webhook[]
     */
    public function getCurrentWebhooks()
    {
        if ($this->webhooks) {
            return $this->webhooks;
        }

        try {
            $this->webhooks = $this->clientFactory->getClient()->getWebhooks()->getItems();
            return $this->webhooks;
        } catch (\Exception $e) {
            $this->logger->error('Failed to get current webhooks: ' . $e->getMessage());
        }
        return array();
    }

    /**
     * Получение ссылки, которая установлена в вебхуках
     *
     * @return string
     */
    public function getCurrentWebhookUrl()
    {
        $currentWebHookList = $this->getCurrentWebhooks();
        if (!isset($currentWebHookList[0])) {
            return '';
        }
        return $currentWebHookList[0]->getUrl();
    }

    /**
     * Список типов уведомлений
     *
     * @return array
     */
    private function getNotificationEventList()
    {
        return array(
            NotificationEventType::PAYMENT_SUCCEEDED,
            NotificationEventType::PAYMENT_CANCELED,
            NotificationEventType::PAYMENT_WAITING_FOR_CAPTURE,
            NotificationEventType::REFUND_SUCCEEDED,
        );
    }

    /**
     * Получение ссылки на уведомления
     *
     * @return string
     */
    public function getNotificationUrl()
    {
        $uri = JURI::getInstance();
        $sslurlhost = 'https://' . $uri->toString(array('host', 'port'));

        $notify_url = $sslurlhost . $this->versionHelper->getSefLink(
                "index.php?option=com_jshopping&controller=checkout&task=step7&act=notify&js_paymentclass=pm_yoomoney&no_lang=1"
            );
        return htmlspecialchars_decode($notify_url);
    }
}
