<?php

namespace App\Game\Services;


use App\Game\BetBy\PlayerDataItem;
use App\Game\GlobalUserInfo;
use App\Notification\TelegramBot;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use App\Game\BetBy\PlayerDetails;
use App\Game\BetBy\PlayerSegment;
use App\Game\BetBy\BonusTemplate;
use App\Game\BetBy\TemplateItem;
use App\Game\BetBy\BonusItem;
use App\Game\BetBy\Bonus;
use App\Game\BetBy\ErrorItem;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Exception;
use Illuminate\Support\Facades\Log;

class BetbyService
{
    protected $client;
    protected $baseUrl;
    public $operatorId;
    public $brandId;
    protected $privateKey;
    protected $publicKey;

    //-----BEGIN PUBLIC KEY-----MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENPcid+kKnpbbW3HuY+m1uRbishkC
    //nhD1k1apZyZUqLy3kmCtBTdKfNaOrk9hjOmJjD84hRBHjwLCgPraOATGAw==-----END PUBLIC KEY-----
    public function __construct()
    {
        $this->client = new Client();

        $this->baseUrl = "https://external-api.invisiblesport.com/api/v1/external_api/";
        $this->operatorId = '2431055242410987528';
        $this->brandId = '2431056314022113280';
        $this->privateKey = '-----BEGIN EC PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgyHuItL+sCjpUTByK
A3jNkUlPIlGOcHBArKC72/6TvHKhRANCAARojqkn6dbPyuIEtT0MeI4hUUZMxabx
2PKTkGp4jxNcjMsCFMQLMRNg5LMXBHyT+IIRlSw2EyQa7zj6RamDu6q6
-----END EC PRIVATE KEY-----';
        $this->publicKey = '-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqjOE0GOdf7wQrMcoy3oX
7AGibUvcDUif58w9J2PDLto1/4+Cp//H7uwSAHQy6ypENvbvx+4U4KS7YcIBB8ry
p8VrSFlQ1UovWmDP+SAP3vf+FyafV93eBeFIjyq9B3ADWVAHNoR2EuRJT429T46k
SZCjYzZCA6QH1mB98XuHjjXBMA5AmJJrHJn8tIVFx//0bpIgijM55iwGC8MzYt3c
74gmk8U6a88KwSYQA3BafsQetmZeh/YbHJ2vmCzkZqpsRjsejsPYud1cEtt1qFL0
MCXCZ17zKuXidktTpUsYa0qLP1X59TzDTLR3txccq1TfyEFfKYpjmTq3H7HPc5r4
K/J0xAsPJLU8r+IysyE3hiO+jheF1JTQKtZnbO6Ul73xZxUN8nqkOFkwTxqiDkIm
jpqV81rbVbZ85OeNuCjdwNCkdaq+jaSNubjW7+vCZUBG7YkzhB2F+AwnbWmLyNuw
GAktH88odLMUIfHr22BQZNTGlAcoDeTps0ZGbHZxMT05yYmGvh1inQlspAmkIY5Q
my6QqaNarnxVYRldiGknJwcwNV2ZpuFn6EQgVIIrdsqfQhsb+zbfrrpVV2Cfbu53
kjUXVyyl5zLa3ijDf4X/ujTIFCH0yvJ6DohMC5TVM6WaunYFVpSrhk5Naiq+dJJF
PpwSndlHML59u+kKz6VtRqsCAwEAAQ==
-----END PUBLIC KEY-----';
    }

    /**
     * 验证并解码JWT payload
     *
     * @param string $token JWT token
     * @return array 解码后的数据
     */
    public function decodePayload(string $token): array
    {
        return (array) JWT::decode($token, new Key($this->publicKey, 'RS256'));
    }

    /**
     * 生成JWT payload
     *
     * @param array $data 数据
     * @return string 生成的JWT token
     */
    public function encodePayload(array $data): string
    {
        $now = time();
        $payload = [
            'iat' => $now,
            'exp' => $now + 3600,
            'jti' => strval(rand()),
            'iss' => $this->brandId,
            'aud' => $this->brandId,
            'nbf' => $now,
            'payload' => $data
        ];
        return JWT::encode($payload, $this->privateKey, 'ES256');
    }
    public function getDefaultJWT($user)
    {

        if(RouteService::isTestSite()) {
            return (new BetbyTestService())->getDefaultJWT($user);
        }
        $user=(array) $user;
        $now = time();
        $payload = [
            'iss' => $this->brandId,
            'sub' => $user['GlobalUID'],
            'name' => $user['NickName'],
            'iat' => $now,
            'exp' => $now + 3600,
            'jti' => strval(rand()),
            'lang'=>$user['DefaultLanguage']??GlobalUserInfo::getLocale(),
            'currency'=>env('CONFIG_24680_CURRENCY')
        ];
        return JWT::encode($payload, $this->privateKey, 'ES256');
    }

    /**
     * 处理请求异常
     *
     * @param RequestException $e 异常对象
     * @return array 错误信息
     */
    private function handleRequestException(RequestException $e): array
    {
        $response = $e->getResponse();
        if ($response) {
            $body = json_decode($response->getBody(), true);
            if (isset($body['error'])) {

                (new TelegramBot())->sendMsgWithEnv($body);
                return [
                    'error' => new ErrorItem($body['error'])
                ];
            }
        }
        return [
            'error' => new ErrorItem(['name' => 'UnknownError', 'description' => 'An unknown error occurred.'])
        ];
    }

    /**
     * 处理响应数据
     *
     * @param $response
     * @return mixed
     */
    private function handleResponse($response)
    {
        $data = json_decode($response->getBody(), true);
        $data= $this->decodePayload($data);
        if (isset($data['error'])) {
            (new TelegramBot())->sendMsgWithEnv($data);
            return ['error' => new ErrorItem($data['error'])];
        }
        return $data;
    }

    public function ping()
    {
        try {
            $response = $this->client->get($this->baseUrl . '/ping' );
            $data = json_decode($response->getBody(),true);
            return $data;
        } catch (RequestException $e) {
            return $this->handleRequestException($e);
        }
    }
    /**
     * 调用Betby的PLAYER_DETAILS接口
     * 获取玩家详细信息
     *
     * @param string $externalPlayerId 玩家ID
     * @param string $segment 分段
     * @param array $depositMethods 存款方式
     * @return PlayerDetails|array
     */
    public function getPlayerDetails(string $externalPlayerId, string $segment, array $depositMethods)
    {
        $payload = $this->encodePayload([
            'external_player_id' => $externalPlayerId,
            'segment' => $segment,
            'deposit_methods' => $depositMethods
        ]);

        try {
            $response = $this->client->post($this->baseUrl . '/player_details', [
                'headers' => ['Content-Type' => 'application/json'],
                'json' => ['payload' => $payload]
            ]);

            $data = $this->handleResponse($response);
            if (isset($data['error'])) {
                return $data;
            }
            return new PlayerDetails($data);
        } catch (RequestException $e) {
            return $this->handleRequestException($e);
        }
    }

    /**
     * 调用Betby的PLAYER_SEGMENT接口
     * 获取玩家分段信息
     *
     * @param string $externalPlayerId 玩家ID
     * @return PlayerSegment|array
     */
    public function getPlayerSegment(string $externalPlayerId)
    {
        $payload = $this->encodePayload([
            'brand_id' => $this->brandId,
            'external_player_id' => $externalPlayerId
        ]);

        try {
            $response = $this->client->post($this->baseUrl . '/player/segment', [
                'headers' => ['Content-Type' => 'application/json'],
                'json' => ['payload' => $payload]
            ]);

            $data = $this->handleResponse($response);
            if (isset($data['error'])) {
                return $data;
            }
            return new PlayerSegment($data);
        } catch (RequestException $e) {
            return $this->handleRequestException($e);
        }
    }

    /**
     * 调用Betby的TEMPLATES接口
     * 获取所有奖金模板
     *
     * @return array<TemplateItem>|array
     */
    public function getBonusTemplates()
    {
        $payload = $this->encodePayload(['operator_id' => $this->operatorId]);

        try {
            $response = $this->client->post($this->baseUrl . '/bonus/templates', [
                'headers' => ['Content-Type' => 'application/json'],
                'json' => ['payload' => $payload]
            ]);

            $data = $this->handleResponse($response);
            if (isset($data['error'])) {
                return $data;
            }
            return array_map(function($template) {
                return new TemplateItem($template);
            }, $data['items']);
        } catch (RequestException $e) {
            return $this->handleRequestException($e);
        }
    }

    /**
     * 调用Betby的TEMPLATE接口
     * 获取指定ID的奖金模板
     *
     * @param string $templateId 奖金模板ID
     * @return TemplateItem|array
     */
    public function getBonusTemplate(string $templateId)
    {
        $payload = $this->encodePayload([
            'operator_id' => $this->operatorId,
            'template_id' => $templateId
        ]);

        try {
            $response = $this->client->post($this->baseUrl . '/bonus/template', [
                'headers' => ['Content-Type' => 'application/json'],
                'json' => ['payload' => $payload]
            ]);

            $data = $this->handleResponse($response);
            if (isset($data['error'])) {
                return $data;
            }
            return new TemplateItem($data);
        } catch (RequestException $e) {
            return $this->handleRequestException($e);
        }
    }

    /**
     * 调用Betby的PLAYER_BONUSES接口
     * 获取玩家的所有奖金
     *
     * @param string $externalPlayerId 玩家ID
     * @return array<BonusItem>|array
     */
    public function getPlayerBonuses(string $externalPlayerId)
    {
        $payload = $this->encodePayload([
            'brand_id' => $this->brandId,
            'external_player_id' => $externalPlayerId
        ]);

        try {
            $response = $this->client->post($this->baseUrl . '/bonus/player_bonuses', [
                'headers' => ['Content-Type' => 'application/json'],
                'json' => ['payload' => $payload]
            ]);

            $data = $this->handleResponse($response);
            if (isset($data['error'])) {
                return $data;
            }
            return array_map(function($bonus) {
                return new BonusItem($bonus);
            }, $data['items']);
        } catch (RequestException $e) {
            return $this->handleRequestException($e);
        }
    }

    /**
     * 调用Betby的BONUS接口
     * NB. Because of technical features one request can contain around 1000 players.
     * Please, split your list of players in case there are significantly more than 1000 players.
     * 获取指定ID的奖金信息
     *
     * @param string $bonusId 奖金ID
     * @return BonusItem|array
     */
    public function getBonus(string $bonusId)
    {
        $payload = $this->encodePayload([
            'brand_id' => $this->brandId,
            'bonus_id' => $bonusId
        ]);

        try {
            $response = $this->client->post($this->baseUrl . '/bonus', [
                'headers' => ['Content-Type' => 'application/json'],
                'json' => ['payload' => $payload]
            ]);

            $data = $this->handleResponse($response);
            if (isset($data['error'])) {
                return $data;
            }
            return new BonusItem($data);
        } catch (RequestException $e) {
            return $this->handleRequestException($e);
        }
    }

    /**
     * 调用Betby的MASS_GIVE_BONUS接口
     * 批量授予奖金
     *
     * @param string $brandId 品牌ID
     * @param string $templateId 奖金模板ID
     * @param PlayerDataItem[] $playersData 玩家数据
     * @return array 响应数据
     */
    public function massGiveBonus(string $brandId, string $templateId, array $playersData): array
    {
        $payload = $this->encodePayload([
            'brand_id' => $brandId,
            'template_id' => $templateId,
            'players_data' => array_map(function($playerData) {
                return [
                    'external_player_id' => $playerData->externalPlayerId,
                    'currency' => $playerData->currency,
                    'amount' => $playerData->amount,
                    'force_activated' => $playerData->forceActivated,
                ];
            }, $playersData)
        ]);

        try {
            $response = $this->client->post($this->baseUrl . '/bonus/mass_give_bonus', [
                'headers' => ['Content-Type' => 'application/json'],
                'json' => ['payload' => $payload]
            ]);

            $data=$this->handleResponse($response);
            if (isset($data['error'])) {
                return $data;
            }
            $bonusItems = [];
            foreach (  $data['result'] as $BonusPlayerItem){
                foreach ($BonusPlayerItem as $playerID => $bonus) {
                    if(isset($bonus['error'])){
                        $bonusItems[$playerID]= ['error'=>new ErrorItem($bonus['error'])];
                    }else{
                        $bonusItems[$playerID] = new BonusItem($bonus);
                    }
                }
            }
            return $bonusItems;
        } catch (RequestException $e) {
            return $this->handleRequestException($e);
        }
    }

    /**
     * 调用Betby的REVOKE_BONUS接口
     * 撤销指定ID的奖金
     *
     * @param string[] $bonuses_ids 奖金IDs
     * @return array<BonusItem>|array
     */
    public function revokeBonus(array $bonuses_ids)
    {
        $payload = $this->encodePayload([
            'brand_id' => $this->brandId,
            'bonus_ids' => $bonuses_ids
        ]);

        try {
            $response = $this->client->post($this->baseUrl . '/bonus/revoke', [
                'headers' => ['Content-Type' => 'application/json'],
                'json' => ['payload' => $payload]
            ]);

            $data=$this->handleResponse($response);
            if (isset($data['error'])) {
                return $data;
            }
            $bonusItems = [];
            foreach (  $data['result'] as $BonusPlayerItem){
                foreach ($BonusPlayerItem as $playerID => $bonus) {
                    if(isset($bonus['error'])){
                        $bonusItems[$playerID]= ['error'=>new ErrorItem($bonus['error'])];
                    }else{
                        $bonusItems[$playerID] = new BonusItem($bonus);
                    }
                }
            }
            return $bonusItems;
        } catch (RequestException $e) {
            return $this->handleRequestException($e);
        }
    }
}
