<?php

class YooMoneyOauth
{
    const OAUTH_CMS_URL = 'https://yookassa.ru/integration/oauth-cms';

    const AUTHORIZATION = 'authorization';
    const GET_TOKEN = 'get-token';
    const REVOKE_TOKEN = 'revoke-token';

    const CMS_NAME = 'drupal';

    /**
     * Формирование данных и отправка запроса на получение ссылки для авторизации
     *
     * @return array
     * @throws Exception
     */
    public static function generateOauthUrl()
    {
        $parameters = array(
            'state' => self::getOauthState(),
            'cms' => self::CMS_NAME,
            'host' => $_SERVER['HTTP_HOST']
        );

        YooMoneyLogger::info('Sending request for OAuth link. Request parameters: ' . json_encode($parameters));

        return self::sendRequest(self::AUTHORIZATION, $parameters);
    }

    /**
     * Формирование данных и отправка запроса на получение токена авторизации
     *
     * @param $state
     * @return array
     * @throws Exception
     */
    public static function generateOauthToken($state)
    {
        $parameters = array('state' => $state);

        YooMoneyLogger::info('Sending request for OAuth token. Request parameters: ' . json_encode($parameters));

        return self::sendRequest(self::GET_TOKEN, $parameters);
    }

    /**
     * Проверяет в БД state и возвращает его, если нет в БД, генерирует его
     *
     * @return string state - уникальный id для запросов в OAuth приложение
     */
    public static function getOauthState()
    {
        $state = variable_get('yoomoney_api_oauth_state');

        if (!$state) {
            $state = substr(md5(time()), 0, 12);
            variable_set('yoomoney_api_oauth_state', $state);
        }

        return $state;
    }

    /**
     * Выполняет запрос в OAuth приложение на отзыв токена
     *
     * @param $token - OAuth токен, который нужно отозвать
     * @param $state - id модуля
     * @return void
     * @throws Exception
     */
    public static function revokeOldToken($token, $state)
    {
        $parameters = array(
            'state' => $state,
            'token' => $token,
            'cms' => self::CMS_NAME
        );

        YooMoneyLogger::info('Sending request to revoke OAuth token. Request parameters: ' . json_encode($parameters));

        $result = self::sendRequest(self::REVOKE_TOKEN, $parameters);

        $body = json_decode($result['response'], true);

        if (!isset($body['success'])) {
            YooMoneyLogger::error(
                'Got error while revoking OAuth token. Response body: '
                . json_encode($body)
            );
        }
    }

    /**
     * Отправка POST запроса и получение данных
     *
     * @param $url
     * @param $parameters
     * @return array
     * @throws Exception
     */
    private static function sendRequest($url, $parameters)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, self::OAUTH_CMS_URL . '/' . $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type' => 'application/json; charset=utf-8'));
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($parameters));
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

        $response = curl_exec($ch);
        $info = curl_getinfo($ch);

        if ($response === false) {
            throw new Exception('Exception: ' . curl_errno($ch) . ": " . curl_error($ch));
        }

        return array('code' => $info['http_code'], 'response' => $response);
    }

    /**
     * Получает информацию о магазине при загрузке страницы с настройками модуля
     *
     * @return void
     * @throws Exception
     */
    public static function saveShopInfoByOauth()
    {
        $apiClient = YooMoneyClientFactory::getYooKassaClient();
        $shopInfo = $apiClient->me();

        if (!isset($shopInfo['account_id'])) {
            throw new Exception('Failed to save shop info');
        }

        variable_set('yoomoney_api_shop_id', $shopInfo['account_id']);
    }
}