<?php

namespace app\service\game;

use addons\webman\model\Game;
use addons\webman\model\GamePlatform;
use addons\webman\model\Player;
use addons\webman\model\PlayerGamePlatform;
use addons\webman\model\PlayerWalletTransfer;
use app\exception\GameException;
use Exception;
use support\Log;
use support\Response;

class JokerServiceInterface extends GameServiceFactory implements GameServiceInterface
{
    public $method = 'POST';
    private $apiDomain;
    private $domain;
    private $appId;
    private $appSecret;
    public $loginId;

    public $gameType = [
        'ECasino' => 'Casino',
        'Fishing' => 'Fishing',
        'Bingo' => 'Bingo',
        'Slot' => 'Slot',
    ];
    
    public $localGameType = [
        'ECasino' => '2',
        'Fishing' => '4',
        'Bingo' => '8',
        'Slot' => '1',
    ];
    
    public $failCode = [
        'S200' => '重復請求',
        'F0001' => '無效的簽名',
        'F0002' => '無效的SN',
        'F0003' => '無效的參數',
        'F0004' => '無效的貨幣',
        'F0005' => '玩家已存在',
        'F0006' => '玩家不存在',
        'F0007' => '會員不存在',
        'F0008' => '執行失敗',
        'F0009' => '無效的方法',
        'F0010' => '無效的用戶狀態',
        'F0011' => '玩家狀態無需更新',
        'F0012' => '超出數據範圍',
        'F0013' => '無匹配數據',
        'F0014' => '登入位置被禁止',
        'F0015' => '分數不足夠',
        'F0016' => '不支持禮碼',
        'F0017' => '交易流水號不得重複',
        'F0018' => '系統繁忙',
        'F0019' => '日期時間各式錯誤',
        'F0020' => '超出時間限制範圍（開始時間與結束時間之間不能大於120分鐘）',
        'F0021' => '執行取消',
        'M0001' => '系統維護',
        'M0002' => '系統錯誤',
    ];

    private $lang = [
        'zh-CN' => 'zh_ch',
        'en' => 'en_us',
        'zh_tc' => 'zh_tc',
        'th_th' => 'th_th',
        'Ma_my' => 'Ma_my',
        'vi_nam' => 'vi_nam',
        'Fi_fi' => 'Fi_fi',
        'Kr_ko' => 'Kr_ko',
        'Hi_hi' => 'Hi_hi',
        'My_mar' => 'My_mar',
        'Br_po' => 'Br_po',
        'cam_dia' => 'cam_dia', // 柬埔寨语
    ];

    /**
     * @param Player|null $player
     * @param $type
     * @throws Exception
     */
    public function __construct($type, Player $player = null)
    {
        $config = config('game_platform.' . $type);
        $this->appId = $config['app_id'];
        $this->apiDomain = $config['api_domain'];
        $this->domain = $config['domain'];
        $this->appSecret = $config['app_secret'];
        $this->platform = GamePlatform::query()->where('name', $type)->first();
        if (!empty($player)) {
            $this->player = $player;
            $this->getLoginId();
        }
    }

    /**
     * 生成请求url
     * @param $method
     * @return string
     */
    public function createUrl($signature): string
    {
        return $this->apiDomain."?AppID=".$this->appId."&Signature=".$signature;
    }

    public function createSign($params): string
    {
        ksort($params);
        $signature = urlencode(base64_encode(hash_hmac("sha1", urldecode(http_build_query($params,'', '&')), $this->appSecret, TRUE)));
        
        return $signature;
    }
    
    /**
     * 更新游戏列表
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getSimpleGameList()
    {
        $params = [
            'Method' => 'ListGames',
            'Timestamp' => time(),
        ];
        $signature = $this->createSign($params);

        $result = doCurl($this->createUrl($signature), $params);
		if (isset($result['ListGames'])) {
			foreach ($result['ListGames'] as $game) {
                Game::query()->updateOrCreate(
                    [
                        'platform_id' => $this->platform->id,
                        'game_code' => $game['GameCode'],
                    ],
                    [
                        'platform_game_type' => $game['GameType'],
                        'game_type' => $this->localGameType[$game['GameType']],
                        'name' => $game['GameName'],
                    ]
                );
            }
		}else{
            throw new GameException($result['Message'], 0);
        }
        return $result;
    }
    
    /**
     * 获取游戏列表
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getGamesList()
    {
        $params = [
            'Method' => 'ListGames',
            'Timestamp' => time(),
        ];
        $signature = $this->createSign($params);

        $result = doCurl($this->createUrl($signature), $params);
		if (isset($result['ListGames'])) {
            return $result;
		}else{
            throw new GameException($result['Message'], 0);
        }
    }

    /**
     * 获取游戏列表
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function playFreeGame()
    {
        $params = [
            'Method' => 'PLAY',
            'Username' => $this->player->name,
            'Timestamp' => time(),
        ];
        $signature = $this->createSign($params);

        $result = doCurl($this->createUrl($signature), $params);
		if (isset($result['Token'])) {
            return $forwardUrl = $this->domain."?token=".$result['Token']."&game=1jeqx59c7ztqg&mobile=false";
        }else{
            throw new GameException($result['Message'], 0);
        }
    }
    
    /**
     * 玩游戏
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function playGame()
    {
        $params = [
            'Method' => 'PLAY',
            'Username' => $this->player->name,
            'RequestID' => createOrderNo(),
            'Amount' => $amount,
            'Timestamp' => time(),
        ];
        $signature = $this->createSign($params);

        $result = doCurl($this->createUrl($signature), $params);
		if (isset($result['Token'])) {
            return $forwardUrl = $this->domain."?token=".$result['Token']."&game=1jeqx59c7ztqg&mobile=false";
        }else{
            throw new GameException($result['Message'], 0);
        }
    }

    /**
     * @throws Exception
     */
    protected function getLoginId()
    {
        /** @var PlayerGamePlatform $playerGamePlatform */
        $playerGamePlatform = $this->player->playerGamePlatform->where('platform_id', $this->platform->id)->first();
        if (!empty($playerGamePlatform)) {
            return $this->loginId = $playerGamePlatform->player_code;
        }
        return $this->createPlayer([
            'uuid' => $this->player->uuid,
            'name' => $this->player->name,
        ]);
    }

    /**
     * 创建玩家
     * @param array $data
     * @return array|mixed|Response
     * @throws GameException|Exception
     */
    public function createPlayer(array $data = [])
    {
        $params = [
            'Method' => 'CU',
            'Username' => $data['uuid'],
            'Timestamp' => time(),
        ];
        $signature = $this->createSign($params);

        $res = doCurl($this->createUrl($signature), $params);
        if (empty($res['Status']) || $res['Status'] != 'OK') {
            Log::error($res['Message'], ['res' => $res]);
            throw new GameException($res['Message'], 0);
        }
        $playerGamePlatform = new PlayerGamePlatform();
        $playerGamePlatform->player_id = $this->player->id;
        $playerGamePlatform->platform_id = $this->platform->id;
        $playerGamePlatform->player_name = $data['name'];
        $playerGamePlatform->player_code = $data['uuid'];
        $playerGamePlatform->save();
        $this->loginId = $playerGamePlatform->player_code;
        return $res;
    }

    /**
     * 获取玩家
     * @return array|mixed|Response
     * @throws GameException|Exception
     */
    public function getPlayer()
    {
        $params = [
            'ID' => createOrderNo(),
            'Method' => 'GetPlayer',
            'SN' => $this->appId,
            'LoginId' => $this->loginId,
        ];
        $params['Signature'] = $this->createSign($params);
        $data = doCurl($this->createUrl('getPlayer'), $params);
        if ($data['code'] != $this->successCode) {
            throw new GameException($this->failCode[$data['code']], 0);
        }

        return $data;
    }

    /**
     * 玩家进入游戏
     * @param array $data
     * @return string
     * @throws GameException|\think\Exception
     */
    public function login(array $data = []): string
    {
        $params = [
            'Method' => 'PLAY',
            'Username' => $this->loginId,
            'RequestID' => createOrderNo(),
            'Amount' => 0,
            'Timestamp' => time(),
        ];
        $signature = $this->createSign($params);

        $res = doCurl($this->createUrl($signature), $params);
        if (empty($res['Token'])) {
            Log::error($res['Message'], ['res' => $res]);
            throw new GameException($res['Message'], 0);
        }
        if (!empty($data['gameCode'])) {
            $link = $this->domain.'?token='.$res['Token'].'&game='.$data['gameCode'].'&mobile=1&lang=en';
        }else{
            $link = $this->domain . ($res['data']['loginUrl'] ?? '') . '&' . $parametersValue;
        }
        return $link;
    }

    /**
     * 设置用户状态
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function setPlayerStatus($status)
    {
        
        $params = [
            'Method' => 'SS',
            'Username' => $this->loginId,
            'Status' => $status,
            'Timestamp' => time(),
        ];
        $signature = $this->createSign($params);

        $res = doCurl($this->createUrl($signature), $params);
        if ($res['Status'] != 'OK') {
            throw new GameException($this->failCode[$res['Status']], 0);
        }

        return $res;
    }

    /**
     * 获取玩家游戏平台余额
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getBalance()
    {
        
        $params = [
            'Method' => 'GC',
            'Username' => $this->loginId,
            'Timestamp' => time(),
        ];
        $signature = $this->createSign($params);

        $res = doCurl($this->createUrl($signature), $params);

        if (empty($res['Credit']) && !empty($res['Message'])) {
            throw new GameException($res['Message'], 0);
        }

        return $res;
    }

    /**
     * 玩家钱包转入游戏平台
     * @return array|mixed|null
     * @throws GameException|\think\Exception
     */
    public function balanceTransferOut()
    {
        return $this->setBalanceTransfer(PlayerWalletTransfer::TYPE_OUT, $this->player->wallet->money);
    }

    /**
     * 游戏平台转入玩家钱包
     * @return array|mixed|null
     * @throws GameException|\think\Exception
     */
    public function balanceTransferIn()
    {
        $params = [
            'Method' => 'WAC',
            'Username' => $this->loginId,
            'Timestamp' => time(),
            'RequestID' => createOrderNo(),
        ];
        $signature = $this->createSign($params);

        $res = doCurl($this->createUrl($signature), $params);

        if (empty($res['RequestID']) || $res['RequestID'] != $params['RequestID'] || $res['Amount'] == 0) {
            throw new GameException($res['Message'], 0);
        }
        // 记录玩家钱包转出转入记录
        $this->createWalletTransfer(PlayerWalletTransfer::TYPE_IN, $res['Amount'], 0, $res['RequestID'] ?? '');

        return $res;
    }

    /**
     *  轉帳進出額度
     *  簽名密鑰方式 MD5 (Id+Method+SN+LoginId+APISecretKey)
     * @param $type
     * @param float $amount
     * @param float $reward
     * @return array|mixed|null
     * @throws GameException|\think\Exception
     */
    protected function setBalanceTransfer($type, float $amount = 0, float $reward = 0)
    {
        if ($amount == 0 && $reward == 0) {
            throw new GameException('转出/入金额错误', 0);
        }
        
        $params = [
            'Method' => 'TC',
            'Username' => $this->loginId,
            'Timestamp' => time(),
            'RequestID' => createOrderNo(),
            'Amount' => $amount,
        ];
        $signature = $this->createSign($params);

        $res = doCurl($this->createUrl($signature), $params);

        if (empty($res['RequestID']) || $res['RequestID'] != $params['RequestID']) {
            // Log::error($res['Message'], ['res' => $res]);
            throw new GameException($res['Message'], 0);
        }
        // 记录玩家钱包转出转入记录
        $this->createWalletTransfer($type, $amount, $reward, $res['RequestID'] ?? '');

        return $res;
    }

    /**
     * 依據時間獲取遊戲紀錄
     * MD5 (Id+Method+SN+StartTime+EndTime+APISecretKey)
     * @param int $pageIndex
     * @param string $startTime
     * @param string $endTime
     * @return array|mixed|null
     * @throws GameException|\think\Exception
     */
    public function getGameRecordByTime(string $startTime = '', string $endTime = '')
    {
        $params = [
            'Method' => 'TSM',
            'StartDate' => $startTime,
            'EndDate' => $endTime,
            'NextId' => '',
            'Delay' => 0,
            'Timestamp' => time(),
        ];
        $signature = $this->createSign($params);

        $res = doCurl($this->createUrl($signature), $params);
        
        // if (empty($res['data'])) {
        //     throw new GameException($res['Message'], 0);
        // }

        return $res;
    }
}