<?php

namespace app\service\game;

use addons\webman\model\Game;
use addons\webman\model\GamePlatform;
use addons\webman\model\GameType;
use addons\webman\model\Player;
use addons\webman\model\PlayerGamePlatform;
use addons\webman\model\PlayerWalletTransfer;
use app\exception\GameException;
use DateTime;
use DateTimeZone;
use Exception;
use Illuminate\Support\Str;
use support\Log;
use support\Response;

class BigGamingServiceInterface extends GameServiceFactory implements GameServiceInterface
{
    public $method = 'POST';
    private $apiDomain;
    private $domain;
    private $appId;
    private $appSecret;
    private $loginId;
    private $sn;
    private $adminUser;
    private $secretCode;

    public $gameType = [
        '2' => 'Casino',
        '5' => 'Fishing',
        '8' => 'Bingo',
        '1' => 'Slot',
    ];

    public $localGameType = [
        '2' => '2',//赌场
        '4' => '4',//捕鱼
        '5' => '5',//真人视讯
    ];

    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' => '系統錯誤',
    ];

    /**
     * @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->sn = $config['sn'];
        $this->adminUser = $config['admin_user'];
        $this->secretCode = base64_encode(sha1($config['admin_pass'], true));
        $this->platform = GamePlatform::query()->where('name', $type)->first();
        if (!empty($player)) {
            $this->player = $player;
            $this->getLoginId();
        }
    }

    /**
     * 生成请求url
     * @return string
     */
    public function createUrl(): string
    {
        return $this->apiDomain;
    }

    //生成签名
    public function createSign($params): string
    {
        $str = '';
        foreach ($params as $v) {
            $str .= $v;
        }
        return md5($str);
    }

    /**
     * 生成请求数据
     * @param $postData
     * @param $method
     * @return array
     */
    public function buildParams($postData, $method): array
    {
        return array(
            "jsonrpc" => "2.0",
            "method" => $method,
            "params" => $postData,
            "id" => $this->player->uuid ?? uniqid()
        );
    }

    /**
     * 创建代理账号
     * @throws GameException|\think\Exception
     */
    public function createAgent()
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'loginId' => 'testagent123',
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        unset($params['secretKey']);
        $params['password'] = '123456ss';
        $postData = $this->buildParams($params, 'open.agent.create');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['result']) && empty($result['error'])){
            return $result;
        }else{
            throw new GameException($result['error']['message'], 0);
        }
    }

    /**
     * 更新游戏列表
     * @return false
     */
    public function getSimpleGameList(): bool
    {
        return false;
    }

    /**
     * 获取玩家ID
     * @throws Exception
     */
    protected function getLoginId()
    {
        /** @var PlayerGamePlatform $playerGamePlatform */
        $playerGamePlatform = PlayerGamePlatform::query()->where('platform_id', $this->platform->id)->where('player_id',$this->player->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 = [
            'random' => $data['uuid'],
            'sn' => $this->sn,
            'secretCode' => $this->secretCode,
        ];
        $params['digest'] = $this->createSign($params);
        $params['loginId'] = $data['uuid'];
        $params['nickname'] = $data['name'];
        $params['agentLoginId'] = $this->adminUser;
        unset($params['secretCode']);
        $postData = $this->buildParams($params, 'open.user.create');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['result']) && empty($result['error'])){
            $playerGamePlatform = new PlayerGamePlatform();
            $playerGamePlatform->player_id = $this->player->id;
            $playerGamePlatform->platform_id = $this->platform->id;
            $playerGamePlatform->player_name = $data['name'];
            $playerGamePlatform->player_code = $result['result']['loginId'];
            $playerGamePlatform->save();
            $this->loginId = $playerGamePlatform->player_code;
            return $result;
        }else{
            throw new GameException($result['error']['message'], 0);
        }
    }

    /**
     * 获取玩家信息
     * @return array|mixed|Response
     * @throws GameException|Exception
     */
    public function getPlayer()
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'loginId' => $this->loginId,
            'secretCode' => $this->secretCode,
        ];
        $params['digest'] = $this->createSign($params);
        unset($params['secretCode']);
        $postData = $this->buildParams($params, 'open.user.get');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['result']) && empty($result['error'])){
            return $result;
        }else{
            throw new GameException($result['error']['message'], 0);
        }
    }

    /**
     * 玩家进入游戏
     * @param array $data
     * @return string
     * @throws GameException|\think\Exception
     */
    public function login(array $data = []): string
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'loginId' => $this->loginId,
            'secretCode' => $this->secretCode,
        ];
        $params['digest'] = $this->createSign($params);
        $params['isMobileUrl'] = 1;
        unset($params['secretCode']);
        $postData = $this->buildParams($params, 'open.video.game.url');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result['result'];
    }

    /**
     * 获取玩家游戏平台余额
     * @throws GameException|\think\Exception
     */
    public function getBalance()
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'loginId' => $this->loginId,
            'secretCode' => $this->secretCode,
        ];
        $params['digest'] = $this->createSign($params);
        unset($params['secretCode']);
        $postData = $this->buildParams($params, 'open.balance.get');
        $result = doCurl($this->apiDomain,$postData);
        if (empty($result['error'])){
            return $result['result'];
        }else{
            throw new GameException('Big Gaming System Error,Please contact the administrator', 0);
        }
    }

    /**
     * 玩家钱包转入游戏平台
     * @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()
    {
        $balance = $this->getBalance();
        return $this->setBalanceTransfer(PlayerWalletTransfer::TYPE_IN, -$balance);
    }

    /**
     *  轉帳進出額度
     * @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) {
            // 记录玩家钱包转出转入记录
            $this->createWalletTransfer($type, $amount, $reward);
            return true;
        }
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'loginId' => $this->loginId,
            'amount' => $amount,
            'secretCode' => $this->secretCode,
        ];
        $params['digest'] = $this->createSign($params);
        unset($params['secretCode']);
        $postData = $this->buildParams($params, 'open.balance.transfer');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        // 记录玩家钱包转出转入记录
        $this->createWalletTransfer($type, $amount, $reward);
        return $result;
    }

    /**
     * 查询额度转移纪录
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getTransferList(string $startTime = '', string $endTime = '', int $page = 1, int $pageSize = 15)
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        $params['loginId'] = $this->loginId;
        $params['startTime'] = $startTime;
        $params['endTime'] = $endTime;
        $params['timeZone'] = 1;
        unset($params['secretKey']);
        $postData = $this->buildParams($params, 'open.balance.transfer.query');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result;
    }

    /**
     * 查询注单统计结果
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getOrderSum(string $startTime = '', string $endTime = '', int $page = 1, int $pageSize = 500)
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        $params['loginIds'] = [$this->loginId];
        $params['startTime'] = $startTime;
        $params['endTime'] = $endTime;
        unset($params['secretKey']);
        $postData = $this->buildParams($params, 'open.sn.order.sum');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result;
    }

    /**
     * 按玩家统计注单
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getUserOrderSum(string $startTime = '', string $endTime = '')
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        $params['startTime'] = $startTime;
        $params['endTime'] = $endTime;
        unset($params['secretKey']);
        $postData = $this->buildParams($params, 'open.user.order.sum');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result['result'];
    }

    /**
     * 查询玩家游戏记录
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getUserGameRecord(string $startTime = '', string $endTime = '')
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'loginId' => $this->loginId,
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        $params['startTime'] = $startTime;
        $params['endTime'] = $endTime;
        unset($params['secretKey']);
        $postData = $this->buildParams($params, 'open.video.round.query');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result['result'];
    }

    /**
     * 查询玩家游戏记录
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function handleOrderHistories()
    {
        try {
            $page = 1;
            $list = [];
            $timezone = new DateTimeZone('America/New_York');
            $start = new DateTime('-6 minutes', $timezone);
            $end = new DateTime('-5 minutes', $timezone);
            $startTime = $start->format('Y-m-d H:i:s');
            $endTime = $end->format('Y-m-d H:i:s');
            $data = $this->getAgentOrderRecord($startTime, $endTime, $page);
            $fishData = $this->getUserFishOrderRecord($startTime, $endTime, $page);
            if (!empty($data['result'])) {
                $total = $data['result']['total'] ?? 0;
                if ($total > 0) {
                    $pageSize = 200;
                    if (!empty($data['result']['items'])) {
                        foreach ($data['result']['items'] as $item) {
                            $list[] = [
                                'uuid' => $item['loginId'],
                                'platform_id' => $this->platform->id,
                                'game_code' => $item['playNameEn'],
                                'bet' => abs($item['bAmount']),
                                'win' => $item['aAmount'],
                                'order_no' => $item['orderId'],
                                'original_data' => json_encode($item,JSON_UNESCAPED_UNICODE),
                                'platform_action_at' => $item['lastUpdateTime'],
                                'game_type' => 5,
                                'created_at' => date('Y-m-d H:i:s'),
                                'updated_at' => date('Y-m-d H:i:s'),
                            ];

                        }
                    }
                    if ($total > $pageSize) {
                        $totalPages = ceil($total / $pageSize);
                        for ($page = 2; $page <= $totalPages; $page++) {
                            $nextData = $this->getAgentOrderRecord($startTime,$endTime,$page);
                            if (!empty($nextData['result']['items'])) {
                                foreach ($nextData['result']['items'] as $item) {
                                    $list[] = [
                                        'uuid' => $item['loginId'],
                                        'platform_id' => $this->platform->id,
                                        'game_code' => $item['playNameEn'],
                                        'bet' => abs($item['bAmount']),
                                        'win' => $item['aAmount'],
                                        'order_no' => $item['orderId'],
                                        'original_data' => json_encode($item,JSON_UNESCAPED_UNICODE),
                                        'platform_action_at' => $item['lastUpdateTime'],
                                        'game_type' => 5,
                                        'created_at' => date('Y-m-d H:i:s'),
                                        'updated_at' => date('Y-m-d H:i:s'),
                                    ];
                                }
                            }
                        }
                    }
                }
            }
            if (!empty($fishData['result'])) {
                $fishTotal = $fishData['result']['total'] ?? 0;
                if ($fishTotal > 0) {
                    $pageSize = 200;
                    if (!empty($fishData['result']['items'])) {
                        foreach ($fishData['result']['items'] as $item) {
                            $list[] = [
                                'uuid' => $item['loginId'],
                                'platform_id' => $this->platform->id,
                                'game_code' => $item['gameType'],
                                'bet' => abs($item['betAmount']),
                                'win' => $item['calcAmount'],
                                'order_no' => $item['betId'],
                                'original_data' => json_encode($item, JSON_UNESCAPED_UNICODE),
                                'platform_action_at' => $item['orderTimeBj'],
                                'game_type' => 4,
                                'created_at' => date('Y-m-d H:i:s'),
                                'updated_at' => date('Y-m-d H:i:s'),
                            ];
                        }
                    }
                    if ($fishTotal > $pageSize) {
                        $totalPages = ceil($fishTotal / $pageSize);
                        for ($page = 2; $page <= $totalPages; $page++) {
                            $nextFishData = $this->getUserFishOrderRecord($startTime,$endTime,$page);
                            if (!empty($nextFishData['result']['items'])) {
                                foreach ($nextFishData['result']['items'] as $item) {
                                    $list[] = [
                                        'uuid' => $item['loginId'],
                                        'platform_id' => $this->platform->id,
                                        'game_code' => $item['gameType'],
                                        'bet' => abs($item['betAmount']),
                                        'win' => $item['calcAmount'],
                                        'order_no' => $item['betId'],
                                        'original_data' => json_encode($item, JSON_UNESCAPED_UNICODE),
                                        'platform_action_at' => $item['orderTimeBj'],
                                        'game_type' => 4,
                                        'created_at' => date('Y-m-d H:i:s'),
                                        'updated_at' => date('Y-m-d H:i:s'),
                                    ];
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception $e) {
            return [];
        }

        return $list;
    }

    /**
     * 查询玩家注单
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getUserOrderRecord(string $startTime = '', string $endTime = '', $page = 1)
    {
        $pageSize = 200;
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        $params['startTime'] = $startTime;
        $params['endTime'] = $endTime;
        $params['pageIndex'] = $page;
        $params['pageSize'] = $pageSize;
        unset($params['secretKey']);
        $postData = $this->buildParams($params, 'open.order.query');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result;
    }

    /**
     * 查询玩家注单详情
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getUserOrderDetail($orderId)
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'orderId' => $orderId,
            'reqTime' => date('Y-m-d H:i:s'),
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        unset($params['secretKey']);
        $postData = $this->buildParams($params, 'open.sn.video.order.detail');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result['result'];
    }

    /**
     * 查询玩家注单详情地址
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getUserOrderDetailUrl($orderId)
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'orderId' => $orderId,
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        unset($params['secretKey']);
        $postData = $this->buildParams($params, 'open.sn.video.order.detail.url.get');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }

        return $result['result'];
    }

    /**
     * 查询玩家捕鱼注单
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getUserFishOrderRecord(string $startTime = '', string $endTime = '', $page = 1)
    {
        $pageSize = 200;
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        $params['gameType'] = 1;
        $params['agentLoginId'] = $this->adminUser;
        $params['startTime'] = $startTime;
        $params['endTime'] = $endTime;
        $params['pageIndex'] = $page;
        $params['pageSize'] = $pageSize;
        unset($params['secretKey']);
        $postData = $this->buildParams($params, 'open.order.bg.query');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result;
    }

    /**
     * 查询代理注单
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getAgentOrderRecord(string $startTime = '', string $endTime = '', $page = 1)
    {
        $pageSize = 200;
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'secretCode' => $this->secretCode,
        ];
        $params['digest'] = $this->createSign($params);
        $params['agentLoginId'] = $this->adminUser;
        $params['startTime'] = $startTime;
        $params['endTime'] = $endTime;
        $params['pageIndex'] = $page;
        $params['pageSize'] = $pageSize;
        unset($params['secretCode']);
        $postData = $this->buildParams($params, 'open.order.agent.query');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result;
    }

    /**
     * 查询投注限红盘口
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getLimitations()
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'time' => date('Y-m-d H:i:s'),
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        unset($params['secretKey']);
        $postData = $this->buildParams($params, 'open.game.limitations.get');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result;
    }

    /**
     * 修改投注限红盘口
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function setLimitations($value)
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'time' => date('Y-m-d H:i:s'),
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        $params['loginId'] = $this->loginId;
        $params['value'] = $value;
        unset($params['secretKey']);
        $postData = $this->buildParams($params, 'open.game.limitations.set');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result;
    }

    /**
     * 获取限红盘口列表
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getLimitationsList()
    {
        $params = [
            'random' => $this->player->uuid ?? uniqid(),
            'sn' => $this->sn,
            'time' => date('Y-m-d H:i:s'),
            'secretKey' => $this->appSecret,
        ];
        $params['sign'] = $this->createSign($params);
        unset($params['secretKey']);
        $postData = $this->buildParams($params, 'open.game.limitations.list');
        $result = doCurl($this->apiDomain,$postData);
        if (!empty($result['error'])) {
            throw new GameException($result['error']['message'], 0);
        }
        return $result;
    }

}