<?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 DateTime;
use DateTimeZone;
use Exception;
use support\Log;
use support\Response;
use WebmanTech\LaravelHttpClient\Facades\Http;

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

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

    public $localGameType = [
        '2' => '2',//赌场
        '5' => '4',//捕鱼
        '8' => '8',//宾果
        'vs' => '1',//斯洛
        'lg' => '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->apiDomain = $config['api_domain'];
        $this->domain = $config['domain'];
        $this->appId = $config['name'];
        $this->secureLogin = $config['secure_login'];
        $this->providerId = $config['provider_id'];
        $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($method): string
    {
        return $this->apiDomain.$method;
    }

    public function createSign($params): string
    {
        ksort($params);
        return md5(http_build_query($params, '', '&') . $this->appSecret);
    }

    /**
     * 更新游戏列表
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getSimpleGameList()
    {
        $params = [
            'secureLogin' => $this->secureLogin,
        ];
        $signature = $this->createSign($params);
        $params['hash'] = $signature;
        $result = doFormCurl($this->createUrl('/IntegrationService/v3/http/CasinoGameAPI/getCasinoGames/'), $params);
        if ($result['error'] == 0 && !empty($result['gameList'])) {
            foreach ($result['gameList'] as $game) {
                if ($game['gameTypeID'] != 'vs') {
                    continue;
                }
                Game::query()->updateOrCreate(
                    [
                        'platform_id' => $this->platform->id,
                        'game_code' => $game['gameID'],
                    ],
                    [
                        'platform_game_type' => $game['gameTypeID'],
                        'game_type' => $this->localGameType[$game['gameTypeID']],
                        'name' => $game['gameName'],
//                        'game_image' => $this->apiDomain.'/gs2c/common/lobby/v1/apps/slots-lobby-assets/'.$game['gameID'].'/'.$game['gameID'].'_325x234_NB.png'
                    ]
                );
            }
        }else{
            throw new GameException($result['description'], 0);
        }
        return $result;
    }

    /**
     * 获取游戏列表
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getGamesList()
    {
        $params = [
            'secureLogin' => $this->secureLogin,
        ];
        $signature = $this->createSign($params);
        $params['hash'] = $signature;
        $result = doFormCurl($this->createUrl('/IntegrationService/v3/http/CasinoGameAPI/getCasinoGames/'), $params);
        if ($result['error'] == 0 && !empty($result['gameList'])) {
            return $result;
        }else{
            throw new GameException($result['description'], 0);
        }
    }

    /**
     * 获取玩家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 = [
            'secureLogin' => $this->secureLogin,
            'externalPlayerId' => $data['uuid'],
            'currency' => 'MYR',
        ];
        $signature = $this->createSign($params);
        $params['hash'] = $signature;
        $result = doFormCurl($this->createUrl('/IntegrationService/v3/http/CasinoGameAPI/player/account/create/'), $params);
        if ($result['error'] != 0 || empty($result['playerId'])) {
            Log::error($result['description'], ['res' => $result]);
            throw new GameException($result['description'], 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 $result;
    }

    /**
     * 获取玩家
     * @return false
     * @throws Exception
     */
    public function getPlayer(): bool
    {
        return false;
    }

    /**
     * 玩家进入游戏
     * @param array $data
     * @return string
     * @throws GameException|\think\Exception
     */
    public function login(array $data = []): string
    {
        $params = [
            'secureLogin' => $this->secureLogin,
            'externalPlayerId' => $this->loginId,
            'gameId' => $data['gameCode'],
            'language' => 'en',
        ];
        $signature = $this->createSign($params);
        $params['hash'] = $signature;
        $result = doFormCurl($this->createUrl('/IntegrationService/v3/http/CasinoGameAPI/game/start/'), $params);
        if ($result['error'] == 0 && !empty($result['gameURL'])) {
            $link = $result['gameURL'];
        }else{
            throw new GameException($result['description'], 0);
        }
        return $link;
    }

    /**
     * 获取玩家游戏平台余额
     * @return array|mixed|Response
     * @throws GameException|\think\Exception
     */
    public function getBalance()
    {
        $params = [
            'secureLogin' => $this->secureLogin,
            'externalPlayerId' => $this->loginId,
        ];
        $signature = $this->createSign($params);
        $params['hash'] = $signature;
        $result = doFormCurl($this->createUrl('/IntegrationService/v3/http/CasinoGameAPI/balance/current/'), $params);
        if ($result['error'] != 0) {
            throw new GameException('Pragmatic System Error,Please contact the administrator', 0);
        }
        return $result['balance'];
    }

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

    /**
     *  轉帳進出額度
     * @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)
    {
        $params = [
            'secureLogin' => $this->secureLogin,
            'externalPlayerId' => $this->loginId,
            'externalTransactionId' => createOrderNo(),
            'amount' => $amount,
        ];
        $signature = $this->createSign($params);
        $params['hash'] = $signature;
        $result = doFormCurl($this->createUrl('/IntegrationService/v3/http/CasinoGameAPI/balance/transfer/'), $params);
        if ($result['error'] != 0) {
            throw new GameException($result['description'], 0);
        }
        // 记录玩家钱包转出转入记录
        $this->createWalletTransfer($type, $amount, $reward, $result['transactionId'] ?? '');
        return $result;
    }

    /**
     *  转账记录
     * @param $startTime
     * @return array|mixed|null
     * @throws GameException
     * @throws \think\Exception
     */
    protected function transferTransactions($startTime)
    {
        $params = [
            'secureLogin' => $this->secureLogin,
            //'timepoint' => $startTime ?? round(microtime(true) * 1000),
        ];
        $signature = $this->createSign($params);
        $params['hash'] = $signature;
        $result = doFormCurl($this->createUrl('/IntegrationService/v3/http/CasinoGameAPI/balance/transfer/transactions/'), $params);
        if ($result['error'] != 0) {
            throw new GameException($result['description'], 0);
        }
        return $result;
    }
    /**
     * 踢出游戏
     * @return array|mixed|Response
     * @throws GameException|Exception
     */
    public function terminateSession()
    {
        $params = [
            'secureLogin' => $this->secureLogin,
            'externalPlayerId' => $this->loginId,
        ];
        $signature = $this->createSign($params);
        $params['hash'] = $signature;
        $result = doFormCurl($this->createUrl('/IntegrationService/v3/http/CasinoGameAPI/game/session/terminate'), $params);
        if ($result['error'] == 0) {
            throw new GameException($result['description'], 0);
        }
        return $result;
    }

    /**
     * 重播链接
     * @return array|mixed|Response
     * @throws GameException|Exception
     */
    public function replayLink($roundId)
    {
        $params = [
            'secureLogin' => $this->secureLogin,
            'externalPlayerId' => $this->loginId,
            'roundId' => $roundId,
        ];
        $signature = $this->createSign($params);
        $params['hash'] = $signature;
        $result = doFormCurl($this->createUrl('/IntegrationService/v3/http/ReplayAPI/getSharedLink'), $params);
        if ($result['error'] == 0) {
            throw new GameException($result['description'], 0);
        }
        return $result;
    }

    /**
     * 查询游戏纪录
     * @return array
     */
    public function getGameRecordList(): array
    {
        $params = [
            'login' => $this->secureLogin,
            'password' => $this->appSecret,
            'timepoint' => round(microtime(true) * 1000) - 90000,
        ];
        $query = http_build_query($params, '', '&');
        $url = $this->createUrl('/IntegrationService/v3/DataFeeds/gamerounds/finished/?' . $query);
        $response = Http::timeout(10)->get($url);
        $result = $response->body();
        return $this->parseCustomCsv($result);
    }

    /**
     * CSV转数组
     * @param $input
     * @return array
     */
    public function parseCustomCsv($input): array
    {
        $lines = explode("\n", trim($input)); // 分割为行数组

        // 解析timepoint
        $timepoint = (int) substr($lines[0], strpos($lines[0], '=') + 1);
        array_shift($lines); // 移除timepoint行

        // 处理CSV部分
        $header = str_getcsv(array_shift($lines)); // 获取标题行
        $result = [
            'timepoint' => $timepoint,
            'data' => []
        ];

        foreach ($lines as $line) {
            $row = str_getcsv($line);
            if (count($row) !== count($header)) continue; // 跳过列数不匹配的行

            // 组合关联数组并转换数据类型
            $entry = array_combine($header, array_map(function($value) {
                if ($value === 'null') return null;         // 转换null字符串
                if (is_numeric($value)) {                   // 转换数字类型
                    return (strpos($value, '.') !== false) ? (float)$value : (int)$value;
                }
                return $value;
            }, $row));

            $result['data'][] = $entry;
        }

        return $result;
    }

    /**
     * 查询玩家游戏记录
     * @return array
     */
    public function handleOrderHistories(): array
    {
        try {
            $list = [];
            $data = $this->getGameRecordList();
            if (!empty($data['data'])) {
                foreach ($data['data'] as $item) {
                    $list[] = [
                        'uuid' => $item['extPlayerID'],
                        'platform_id' => $this->platform->id,
                        'game_code' => $item['gameID'],
                        'bet' => $item['bet'],
                        'win' => $item['win'],
                        'order_no' => $item['playSessionID'],
                        'original_data' => json_encode($item,JSON_UNESCAPED_UNICODE),
                        'platform_action_at' => date('Y-m-d H:i:s', strtotime($item['endDate'])),
                        'game_type' => 'vs',
                        'created_at' => date('Y-m-d H:i:s'),
                        'updated_at' => date('Y-m-d H:i:s'),
                    ];

                }
            }
        } catch (Exception $e) {
            return [];
        }

        return $list;
    }

}