<?php


namespace CCDN\Helpers\Api;


use CCDN\Helpers\Facade\Http\Request;
use http\Exception\RuntimeException;

class Client
{

    /**
     * @var string
     */
    private $domain;

    /**
     * @var int
     */
    private $timeOut;

    /**
     * @var resource|false
     */
    private $curl;

    /**
     * Client constructor.
     * @param  string  $domain
     * @param  int  $timeOut
     */
    public function __construct($domain = null, $timeOut = 10)
    {
        if ($domain !== null) {
            $this->domain = rtrim($domain, '/');
        }
        $this->timeOut = $timeOut;
        $this->createConfig();
    }

    private function createConfig()
    {
        $this->curl = curl_init();
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->timeOut);
        curl_setopt($this->curl, CURLOPT_HEADER, 0);
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($this->curl, CURLOPT_USERAGENT, Request::getUserAgent());
    }

    /**
     * @param  string  $path
     * @param  null|array  $query
     * @return string
     */
    private function buildUrl($path, $query = null)
    {
        $queryStr = '';
        if (!empty($query)) {
            $queryStr = '?'.http_build_query($query);
        }

        $path = ltrim($path, '/');
        if ($this->domain !== null) {
            return $this->domain.'/'.$path.$queryStr;
        }
        return $path.$query;
    }

    /**
     * @param  string  $path
     * @param  null|array  $query
     * @return string
     */
    public function get($path, $query = null)
    {
        $url = $this->buildUrl($path, $query);
        curl_setopt($this->curl, CURLOPT_URL, $url);
        $data = curl_exec($this->curl);

        if (curl_errno($this->curl) !== 0) {
            throw new RuntimeException('Curl error: '.curl_error($this->curl));
        }

        $http_code = curl_getinfo($this->curl);

        if ($http_code['http_code'] >= 400) {
            throw new RuntimeException('Http error: '.json_encode($http_code, JSON_UNESCAPED_UNICODE));
        }

        curl_close($this->curl);

        return $data;
    }


    /**
     * @param  string  $path
     * @param  null|array  $queries
     * @return array
     */
    public function getAsync($path, $queries = null)
    {

        $curlSessions = [];
        $results = [];

        $curlMulti = curl_multi_init();

        foreach ($queries as $key => $query) {
            $curlSessions[$key] = curl_init();
            $url = $this->buildUrl($path, $query);
            curl_setopt($curlSessions[$key], CURLOPT_URL, $url);
            curl_setopt($curlSessions[$key], CURLOPT_TIMEOUT, $this->timeOut);
            curl_setopt($curlSessions[$key], CURLOPT_HEADER, 0);
            curl_setopt($curlSessions[$key], CURLOPT_RETURNTRANSFER, true);
            curl_multi_add_handle($curlMulti, $curlSessions[$key]);
        }

        $active = null;
        do {
            $mrc = curl_multi_exec($curlMulti, $active);
        } while ($mrc === CURLM_CALL_MULTI_PERFORM);

        while ($active && $mrc === CURLM_OK) {
            if (curl_multi_select($curlMulti) === -1) {
                continue;
            }

            do {
                $mrc = curl_multi_exec($curlMulti, $active);
            } while ($mrc === CURLM_CALL_MULTI_PERFORM);
        }

        foreach ($curlSessions as $key => $channel) {
            if (curl_errno($channel) !== 0) {
                throw new RuntimeException('Curl error: '.curl_error($channel));
            }
            $results[$key] = curl_multi_getcontent($channel);
            curl_multi_remove_handle($curlMulti, $channel);
        }

        curl_multi_close($curlMulti);

        return $results;
    }
}
