<?php

namespace trader\exchange\bybit;

require_once __DIR__ . '/../../struct/ApiInfo.php';
require_once __DIR__ . '/../../../jiaoyin/func.php';
require_once __DIR__ . '/../../../jiaoyin/Curl.php';

use trader\struct\ApiInfo;
use Jiaoyin\Curl;
use function Jiaoyin\getMicrotime;

class Api
{
    private $host = 'https://api.bybit.com';
    private ?ApiInfo $apiInfo;

    public function __construct(?ApiInfo $apiInfo)
    {
        $this->apiInfo = $apiInfo;
    }

    public function setHost($host)
    {
        $this->host = $host;
    }

    //----------- public interface ------------
    // 获取交易对信息
    public function instruments($param)
    {
        $path = "/v5/market/instruments-info";
        $method = 'GET';
        return $this->request($path, $method, $param);
    }

    // 获取K线数据
    public function klines($param)
    {
        $path = "/v5/market/kline";
        $method = 'GET';
        return $this->request($path, $method, $param);
    }

    //----------- private interface ------------
    // 下单
    public function placeOrder($param)
    {
        $path = '/v5/order/create';
        $method = 'POST';
        return $this->request($path, $method, $param, true);
    }

    // 查询持仓
    public function getPositions($param)
    {
        $path = '/v5/position/list';
        $method = 'GET';
        return $this->request($path, $method, $param, true);
    }

    // 设置杠杆
    public function setLeverage($param)
    {
        // 确保杠杆值为字符串类型
        if (isset($param['buyLeverage'])) {
            $param['buyLeverage'] = (string)$param['buyLeverage'];
        }
        if (isset($param['sellLeverage'])) {
            $param['sellLeverage'] = (string)$param['sellLeverage'];
        }
        $path = '/v5/position/set-leverage';
        $method = 'POST';
        return $this->request($path, $method, $param, true);
    }

    // 查询账户余额
    public function accountBalance($param)
    {
        $path = '/v5/account/wallet-balance';
        $method = 'GET';
        return $this->request($path, $method, $param, true);
    }

    //-------------------------------------
    private function createSign($timestamp, $method, $path, $params = [])
    {
        $recv_window = '5000';
        $sign_str = $timestamp . $this->apiInfo->key . $recv_window;

        if ($method == 'GET' && !empty($params)) {
            $sign_str .= http_build_query($params);
        } else if ($method == 'POST' && !empty($params)) {
            $sign_str .= json_encode($params);
        }

        $sign = hash_hmac('sha256', $sign_str, $this->apiInfo->secret);
        return $sign;
    }

    private function request($path, $method, $param, $auth = false)
    {
        $header = [];
        $body = '';
        $fullPath = $path;
        $timestamp = getMicrotime();

        if ($method == 'GET' && !empty($param)) {
            $fullPath = $path . '?' . http_build_query($param);
        } else {
            $header[] = 'Content-Type: application/json';
            $body = json_encode($param);
        }

        if ($auth) {
            $header[] = 'X-BAPI-API-KEY: ' . $this->apiInfo->key;
            $header[] = 'X-BAPI-TIMESTAMP: ' . $timestamp;
            $header[] = 'X-BAPI-RECV-WINDOW: 5000';
            $header[] = 'X-BAPI-SIGN: ' . $this->createSign($timestamp, $method, $path, $param);
        }

        $url = $this->host . $path;
        $result = "";
        if ($method == 'POST') {
            $result = Curl::httpPost($url, $param, $header);
        } else {
            $result = Curl::httpGet($url, $param, $header);
        }

        return json_decode($result, true);
    }
}