<?php
/*
 * ----------------------------------------------------------------------
 *
 *                          Borlabs Cookie
 *                      developed by Borlabs
 *
 * ----------------------------------------------------------------------
 *
 * Copyright 2018 Borlabs - Benjamin A. Bornschein. All rights reserved.
 * This file may not be redistributed in whole or significant part.
 * Content of this file is protected by international copyright laws.
 *
 * ----------------- Borlabs Cookie IS NOT FREE SOFTWARE -----------------
 *
 * @copyright Borlabs - Benjamin A. Bornschein, https://borlabs.io
 * @author Benjamin A. Bornschein, Borlabs ben@borlabs.io
 *
 */

namespace BorlabsCookie\Cookie;

use BorlabsCookie\Cookie\HMAC;
use BorlabsCookie\Cookie\Backend\License;

class API
{

    private static $instance;

    private $apiURL = 'https://api.cookie.borlabs.io/v3';
    private $updateURL = 'https://update.borlabs.io/v1';
    private $response = [];

    public static function getInstance()
    {
        if (null === self::$instance) {
            self::$instance = new self;
        }

        return self::$instance;
    }

    private function __clone()
    {
    }

    private function __wakeup()
    {
    }

    public function __construct()
    {
    }

    /**
     * addVars function.
     *
     * @access public
     * @param mixed $vars
     * @return void
     */
    public function addVars($vars)
    {
        $vars[] = '__borlabsCookieCall';

        return $vars;
    }

    /**
     * detectRequests function.
     *
     * @access public
     * @return void
     */
    public function detectRequests()
    {
        global $wp;

        if (!empty($wp->query_vars['__borlabsCookieCall'])) {

            $data = json_decode(file_get_contents("php://input"));

            $this->handleRequest($wp->query_vars['__borlabsCookieCall'], $data);

            exit;
        }
    }

    /**
     * handleRequest function.
     *
     * @access public
     * @param mixed $call
     * @param mixed $token
     * @param mixed $data
     * @return void
     */
    public function handleRequest($call, $data)
    {
        // Check if request is authorized
        if ($this->isAuthorized($data)) {

            if ($call == 'updateLicense') {

                $this->updateLicense($data);

            }
        }
    }

    /**
     * getPluginInformation function.
     *
     * @access public
     * @return void
     */
    public function getPluginInformation()
    {
        $response = wp_remote_post(
            $this->updateURL.'/plugin-information/'.(defined('BORLABS_COOKIE_DEV_BUILD') && BORLABS_COOKIE_DEV_BUILD == true ? 'dev-' : '').dirname(BORLABS_COOKIE_SLUG),
            [
                'timeout'   =>45,
                'body'      =>[
                    'version'=>BORLABS_COOKIE_VERSION,
                    'product'=>dirname(BORLABS_COOKIE_SLUG),
                ]
            ]
        );

        if (!empty($response) && is_array($response) && !empty($response['body'])) {
            $body = json_decode($response['body']);

            if (!empty($body->success) && !empty($body->pluginInformation)) {
                return unserialize($body->pluginInformation);
            }
        }
    }

    /**
     * getLatestVersion function.
     *
     * @access public
     * @return void
     */
    public function getLatestVersion()
    {
        $response = wp_remote_post(
            $this->updateURL.'/latest-version/'.(defined('BORLABS_COOKIE_DEV_BUILD') && BORLABS_COOKIE_DEV_BUILD == true ? 'dev-' : '').dirname(BORLABS_COOKIE_SLUG),
            [
                'timeout'   =>45,
                'body'      =>[
                    'version'=>BORLABS_COOKIE_VERSION,
                    'product'=>dirname(BORLABS_COOKIE_SLUG),
                ]
            ]
        );

        if (!empty($response) && is_array($response) && !empty($response['body'])) {
            $body = json_decode($response['body']);

            if (!empty($body->success) && !empty($body->updateInformation)) {
                return unserialize($body->updateInformation);
            }
        }
    }

    /**
     * updateLicense function.
     *
     * @access public
     * @param mixed $data
     * @return void
     */
    public function updateLicense($data)
    {
        if (!empty($data->licenseKey)) {
            License::getInstance()->saveLicenseData($data);
        } elseif (!empty($data->removeLicense)) {
            License::getInstance()->removeLicense();
        }

        echo json_encode([
            'success'=>true,
        ]);
    }

    public function registerLicense($licenseKey)
    {
        $url = is_multisite() ? network_site_url() : get_site_url();
        $urlWordPress = get_home_url();

        $data = [
            'licenseKey'=>$licenseKey,
            'url'=>$url,
            'email'=>'',
            'urlWordPress'=>($url != $urlWordPress ? $urlWordPress : ''),
            'version'=>BORLABS_COOKIE_VERSION,
        ];

        // Register site
        $response = $this->restPostRequest('/register', $data);

        if (!empty($response->licenseKey)) {

            // Save license data
            License::getInstance()->saveLicenseData($response);

            return (object) [
                'success'=>true,
                'successMessage'=>_x('License registered successfully.', 'API - Success Message', 'borlabs-cookie'),
            ];
        } elseif (!empty($response->unlink)) {
            // License is already used and the unlink routine was triggered
            update_site_option('BorlabsCookieUnlinkData', (object) ['licenseKey'=>$licenseKey, 'unlink'=>$response->unlink], 'no');

            return $response;
        } else {
            return $response;
        }
    }

    /**
     * unlinkWebsite function.
     *
     * @access public
     * @param mixed $licenseKey
     * @param mixed $unlinkSiteHash
     * @return void
     */
    public function unlinkWebsite($licenseKey, $unlinkSiteHash)
    {
        $data = [
            'licenseKey'=>$licenseKey,
            'hash'=>$unlinkSiteHash,
        ];

        // Unlink website
        $response = $this->restPostRequest('/register/unlink', $data);

        if (!empty($response->unlink)) {

            delete_site_option('BorlabsCookieUnlinkData');

            return (object) [
                'success'=>true,
                'successMessage'=>_x('Selected website unlinked successfully. You can now re-enter your license key to register this website.', 'API - Success Message', 'borlabs-cookie'),
            ];
        } else {
            return $response;
        }
    }

    /**
     * getNews function.
     *
     * @access public
     * @return void
     */
    public function getNews()
    {
        // Unlink website
        $response = $this->restPostRequest('/news', []);

        if (!empty($response->success)) {

            update_site_option('BorlabsCookieNews', $response->news);
            // Update last check
            update_site_option('BorlabsCookieNewsLastCheck', date('Ymd'), 'no');

            return (object) [
                'success'=>true,
            ];
        } else {
            return $response;
        }
    }

    /**
     * restPostRequest function.
     *
     * @access private
     * @param mixed $route
     * @param mixed $data
     * @param mixed $salt (default: null)
     * @return void
     */
    private function restPostRequest($route, $data, $salt = null)
    {
        $args = [
            'timeout'=>45,
            'body'=>$data,
        ];

        // Add authentification header
        if (!empty($salt)) {
            $args['headers'] = [
                'X-Borlabs-Cookie-Auth'=>HMAC::getInstance()->hash($data, $salt),
            ];
        }

        // Make post request
        $response = wp_remote_post(
            $this->apiURL.$route,
            $args
        );

        if (!empty($response) && is_array($response) && $response['response']['code'] == 200 && !empty($response['body'])) {

            $responseBody = json_decode($response['body']);

            if (empty($responseBody->error)) {
                return $responseBody;
            } else {
                // Borlabs Cookie API messages
                $responseBody->errorMessage = $this->translateErrorCode($responseBody->errorCode, $responseBody->message);

                return $responseBody;
            }
        } else {
            if (!empty($response['response']['message'])) {
                // Server message
                return (object) [
                    'errorMessage'=>$response['response']['code'].' '.$response['response']['message'],
                ];
            } else {
                // WP_Error messages
                return (object) [
                    'errorMessage'=>implode('<br>', $response->get_error_messages())
                ];
            }
        }
    }

    /**
     * translateErrorCode function.
     *
     * @access private
     * @param mixed $errorCode
     * @return void
     */
    private function translateErrorCode($errorCode, $message = '')
    {
        $errorMessage = '';

        if ($errorCode == 'accessError') {

            $errorMessage = _x('The request was blocked. Please try again later.', 'API - Error Message', 'borlabs-cookie');

        } elseif ($errorCode == 'hadTrialBefore') {

            $errorMessage = _x('Your website already had a Trial License and can not get a Trial Version a second time.', 'API - Error Message', 'borlabs-cookie');

        } elseif ($errorCode == 'switchToTrial') {

            $errorMessage = sprintf(_x('An error occured while switching the license to a Trial License. Please contact the support. %s', 'API - Error Message', 'borlabs-cookie'), $message);

        } elseif ($errorCode == 'trialNotPossible') {

            $errorMessage = _x('A Trial License is only available for Personal Licenses.', 'API - Error Message', 'borlabs-cookie');

        } elseif ($errorCode == 'unlinkRoutine') {

            $errorMessage = _x('Your license key is already being used by another website.', 'API - Error Message', 'borlabs-cookie');

        } elseif ($errorCode == 'unlinkRoutineForTrialLicense') {

            $errorMessage = _x('A Trial License key can not be moved to another website.', 'API - Error Message', 'borlabs-cookie');

        } elseif ($errorCode == 'validateHash') {

            $errorMessage = sprintf(_x('The request to the API could not be validated. %s', 'API - Error Message', 'borlabs-cookie'), $message);

        } elseif ($errorCode == 'invalidLicenseKey') {

            $errorMessage = _x('Your license key is not valid.', 'API - Error Message', 'borlabs-cookie');

        } else {
            // errorCode == error
            $errorMessage = sprintf(_x('An error occurred. Please contact the support. %s', 'API - Error Message', 'borlabs-cookie'), $message);
        }

        return $errorMessage;
    }
}
