<?php

/**
 * EOS相关操作
 * User: ben
 * Date: 2018/9/19
 * Time: 下午2:59
 */
class Eos extends EosBase {
    const REDIS_SERV = 'dw_baccarat';

    const KEY_BALANCE_LIST = "globals:dw_baccarat:balance_list";
    const PRE_SIGN_MAP = "globals:dw_baccarat:sign_map:";
    const PRE_CREATE_TRANS_MAP = "globals:dw_baccarat:create_trans_map:";
    const PRE_ROOM_REWARD = 'globals:dw_baccarat:room_reward:';

    const ROOM_LIMIT = 10;
    const LIVE_LIMIT = 20;

    static $objRedisMap = [];

    function __construct() {
        // 解锁钱包
        $this->unlockWallet();
    }

    static function pubEvent($event, $data, $cacheKey = self::REDIS_SERV) {
//        dwRedis::cleanInstance();
//        $objRedis = dwRedis::init('dw_box');
        if (!self::$objRedisMap[$cacheKey]) {
            self::$objRedisMap[$cacheKey] = dwRedis::initNewOne($cacheKey);
        }

        if (is_array($data)) {
            $data = json_encode($data);
        }

        return self::$objRedisMap[$cacheKey]->publish($event, $data);
    }

    /**
     * 创建游戏
     * @return array
     */
    public function createGame($sync = true) {
        $lockKey = 'do_create';
        $objLock = new Lock('createGame', 2);
        $flag = $objLock->lock($lockKey, false);
        if (!$flag) {
            return [];
        }
        $id = $this->_getNewGame();


        $cmd = "cleos -u {$GLOBALS['eosUrl']} push action {$GLOBALS['codeBaccarat']} creategame '[{$id}]' -p {$GLOBALS['codeBaccarat']} -j ";
        $json = self::execCmd($cmd);
        $log = [
            'transaction_type' => 'createGame',
            'from' => $GLOBALS['codeBaccarat'],
            'to' => $GLOBALS['codeBaccarat'],
            'cmd' => $cmd,
            'json' => $json,
        ];
        // 记录交易，失败重试
        $data = self::logTrans($log);
        $data['gameid'] = $id;

        Eos::log("cmd: {$cmd}");
        Eos::log("json: {$json}");

        // 同步数据
        if ($sync) {
//            $this->syncGame();
            $objSyncGame = new Sync_Game();
            $objSyncGame->pubSubscribe(false);
        }

        $objLock->unlock($lockKey);

        return $data;
    }

    /**
     * 开奖并创建游戏
     * @param $game
     * @param null $objGame
     * @return int
     * @throws DB_Exception
     */
    public function revealCreate($game, $objGame = null) {
        !$objGame && $objGame = new Game();

        if (!$game['create_block_num']) {
            $msg = "game:{$game['id']} is error, create_block_num not found";
            Eos::log($msg);
            alermErrorMsg($msg);
            return null;
        }

        $newGameId = $this->_getNewGame();
//        $commitment = $info['commitment'];
        if ($newGameId == $game['id']) {
            alermErrorMsg("revealCreate error. newGameId:{$newGameId} == gameid:{$game['id']}");
            return null;
        }

        // 获取开奖数据
        if ($game['revealInfo']) {
            $revealInfo = json_decode($game['revealInfo'], true);
            $win = $revealInfo['win'];
            $playerPoker = $revealInfo['player'];
            $bankerPoker = $revealInfo['banker'];
            $playerPair = $revealInfo['playerPair'];
            $bankerPair = $revealInfo['bankerPair'];
            $revealBlockNum = $revealInfo['revealBlockNum'];
        } else {
            try {
                list($win, $playerPoker, $bankerPoker, $playerPair, $bankerPair, $revealBlockNum, $revealInfo) = Game::revealGameData($game['create_block_num'], $game['ttl']);
            } catch (Exception $e) {
                Eos::log($e->getMessage());
                return null;
            }

        }

        $playerPoker = sprintf("[%s]", implode(', ', $playerPoker));
        $bankerPoker = sprintf("[%s]", implode(', ', $bankerPoker));
        $playerPair = $playerPair ? 'true' : 'false';
        $bankerPair = $bankerPair ? 'true' : 'false';

        $cmd = "cleos -u {$GLOBALS['eosUrl']} push action {$GLOBALS['codeBaccarat']} revealcreate '[ {$game['id']}, {$bankerPoker}, {$playerPoker}, {$bankerPair}, {$playerPair}, {$win}, {$newGameId}]' -p {$GLOBALS['codeBaccarat']} -j ";
        $json = self::execCmd($cmd);

        $log = [
            'transaction_type' => 'revealcreate',
            'from' => $GLOBALS['codeBaccarat'],
            'to' => $GLOBALS['codeBaccarat'],
            'cmd' => $cmd,
            'json' => $json,
        ];
        // 记录交易，失败重试
        $trans = self::logTrans($log);
        $trxId = $trans['transaction_id'];

        if ($trxId) {
            $newData = [
                'reveal_trx_id' => $trxId,
            ];
            if (!$game['revealInfo']) {
                $newData['reveal_block_num'] = $revealBlockNum;
                $newData['reveal_info'] = json_encode($revealInfo);
            }
            $objGame->objTable->updateObject($newData, ['id' => $game['id']]);

            // 开奖成功转账 balance
            $objOffer = new Offer();
            $players = $objOffer->getGamePlayer($game['id']);
            foreach ($players as $player => $offerTrxId) {
                self::balance($game['id'], $player, $offerTrxId);
            }

            return $newGameId;
        } else {
            $msg = "开奖超时，gameid:{$game['id']}, json:{$json}";
            alermErrorMsg($msg);

            return null;
        }
    }

    private function _getNewGame() {
        $objGame = new TableHelper('game', 'dw_baccarat');
        $keyWord = [
            '_sortKey' => 'id DESC',
            '_field' => 'id',
            'game_state' => [1, 2]
        ];

        $row = $objGame->getRow($keyWord);
        $id = (int) date("Ymd00010001");
        $id2 = (int) $row['id'];
        if ($id2 >= $id) {
            $id = $id2 + 1;
        }

        return $id;
    }

    /**
     * 块信息
     * @param $blockId
     * @return array
     */
    public static function getBlockInfo($blockId) {
        $cmd = "cleos -u https://api.eosnewyork.io get block '{$blockId}'";
        $json = self::execCmd($cmd);
        return json_decode($json, true);
    }

    /**
     * 获取块id
     * @param $block_num
     *
     * @return array
     */
    public static function getBlockId($block_num) {
        $cmd = "cleos -u {$GLOBALS['eosUrl']} get block {$block_num}";
        $json = self::execCmd($cmd);

        $json = str_replace("\n", '', $json);
        $info = json_decode($json, true);

        if ($info && $info['id']) {
            $block_id = $info['id'];
        } else {
            $hex = dechex($block_num);
            $hex = sprintf("%08s", $hex);
            preg_match("/\"({$hex}[0-9a-fA-F]{56})\"/", $json, $matches);
            $block_id = $matches[1];
        }

        return $block_id;
    }

    /**
     * 提现接口
     * @param $player
     * @param $eos
     * @return array $transaction_id
     */
    function withdraw($player, $eos) {
        $memo = "withdraw";
        return $this->transfer($GLOBALS['codeBaccarat'], $player, $eos, $memo, 'withdraw');
    }

    /**
     * 回收gt币接口
     * @param $player
     * @param $eos
     * @return array $transaction_id
     */
    function buyback($player, $eos) {
        $memo = "buyback|1";
        return $this->transfer($GLOBALS['codeGtAdmin'], $player, $eos, $memo, 'buyback');
    }

    /**
     * 提现分红接口
     * @param $player
     * @param $eos
     * @return array $transaction_id
     */
    function withdrawBonus($player, $eos) {
        $memo = "withdraw bonus";
        return $this->transfer($GLOBALS['codeGtAdmin'], $player, $eos, $memo, 'withdraw bonus');
    }

    /**
     * 游戏分红
     * @param $gameid
     * @param $bonus
     * @param $buyback
     *
     * @return array
     */
    function gamebalance($gameid, $bonus, $buyback) {
        $memo = "gamebalance|{$gameid}|{$buyback}|{$bonus}";

        $eos = sprintf("%.4f EOS", round(($buyback + $bonus) / 10000, 4));
        return $this->transfer($GLOBALS['codeBaccarat'], $GLOBALS['codeGtAdmin'], $eos, $memo, 'gamebalance');
    }

    /**
     * 结算转账接口
     * @param int $gameid
     * @param string $userName
     * @return string
     */
    public static function balance($gameid, $userName, $player_transaction_id) {
        $cmd = "cleos -u {$GLOBALS['eosUrl']} push action {$GLOBALS['codeBaccarat']} balance '[ {$gameid}, \"{$userName}\" ]'  -j -p {$GLOBALS['codeBaccarat']}";
        $json = self::execCmd($cmd);

        $log = [
            'player_transaction_id' => $player_transaction_id,
            'transaction_type' => 'balance',
            'from' => $GLOBALS['codeBaccarat'],
            'to' => $userName,
            'cmd' => $cmd,
            'json' => $json,
        ];
        // 记录交易，失败重试
        self::logTrans($log);

        return $json;
    }

    /**
     * 结算转账接口
     * @param string $userName
     * @param string $eos
     * @param string $gameid
     * @param string $betEos
     * @param string $player_transaction_id
     * @return array
     */
    function dig($userName, $eos, $gameid, $betEos, $player_transaction_id = '') {
        $from = $GLOBALS['codeGtAdmin'];
        $memo = "【https://eosget.io】Dig in Box {$gameid}";


        $cmd = "cleos -u {$GLOBALS['eosUrl']} push action {$from} dig '[ \"{$userName}\", \"{$eos}\", \"{$memo}\", \"{$betEos}\" ]'  -j -p {$from}";
        $json = self::execCmd($cmd);

        $log = [
            'player_transaction_id' => $player_transaction_id,
            'transaction_type' => 'dig',
            'from' => $from,
            'to' => $userName,
            'cmd' => $cmd,
            'json' => $json,
        ];
        // 记录交易，失败重试
        $trans = self::logTrans($log);

        if (!$trans['transaction_id']) {
            alermErrorMsg("挖矿异常，player:{$userName}, eos:{$eos}, json:{$json}");
        }

        return $trans;
    }

    function _formatDateTime($str) {
        if (strpos($str, 'T') > 0) {
            return date('Y-m-d H:i:s', strtotime($str) + 8 * 3600);
        } else {
            return date('Y-m-d H:i:s', strtotime($str));
        }
    }



    public static function getAccountActions($account_name, $limit = 200) {
//        $cmd = "cleos -u {$GLOBALS['eosUrl']} get actions {$account_name} -1 -{$limit} -j";
        if (ENV == ENV_DEV) {
            $url = $GLOBALS['eosUrl'];
        } else {
            // 正式环境，要查历史数据，只能用 nodes.get-scatter.com
            $url = 'https://nodes.get-scatter.com';
        }

        $cmd = "cleos -u {$url} get actions {$account_name} -1 -{$limit} -j";
        $json = self::execCmd($cmd);

        return json_decode($json, true);
    }

    /**
     * 获取gt推广奖励
     * @param $player
     * @param $invite_friend
     * @param $amount
     * @return array
     */
    public function getGtReward($player, $invite_friend, $amount) {
        $memo = "invite friend:" . $invite_friend;
        return $this->transfer($GLOBALS['codeGtAdmin'], $player, $amount, $memo, 'invite friend');
    }


    /**
     * 获取用户gt
     * @param $player
     */
    public static function getAccountGt($player) {
        $cmd = "cleos -u {$GLOBALS['eosUrl']} get currency balance eosgetgtoken {$player} gt";
        $ret = self::execCmd($cmd);
        return $ret;
    }

    /**
     * gt 重新质押
     * @param $player
     * @param $gt_amount
     */
    public function restake($player, $gt_amount) {
        $cmd = "cleos -u {$GLOBALS['eosUrl']}  push action {$GLOBALS['codeGtAdmin']} restake '[\"{$player}\", \"{$gt_amount}\"]' -p {$GLOBALS['codeGtAdmin']} -j";
        $ret = self::execCmd($cmd);
        return json_decode($ret, true);
    }

    /**
     * gt 解冻用户赎回gt
     * @param $player
     * @param $gt_amount
     * @return array
     */
    public function unfreeze($player, $gt_amount) {
        $cmd = "cleos -u {$GLOBALS['eosUrl']} push action {$GLOBALS['codeGtAdmin']} unfreeze '[\"{$player}\", \"{$gt_amount}\"]' -p {$GLOBALS['codeGtAdmin']} -j";

        $ret = self::execCmd($cmd);
        return json_decode($ret, true);
    }

    /*
     * gt 分红
     * @param $player
     * @param $gt_amount
     */
    public function bonus() {
        // cleos -u http://61.160.36.19:7777/ push action eosgetadmin1 bonus '' -p eosgetadmin1
        $cmd = "cleos -u {$GLOBALS['eosUrl']}  push action {$GLOBALS['codeGtAdmin']} bonus '' -p {$GLOBALS['codeGtAdmin']} -j";

        $ret = self::execCmd($cmd);
        return json_decode($ret, true);
    }

    public function unstake($player, $gt_amount) {
        $cmd = "cleos -u {$GLOBALS['eosUrl']}  push action {$GLOBALS['codeGtAdmin']} unstake '[\"{$player}\", \"{$gt_amount}\"]' -p {$player} -j";
        $ret = self::execCmd($cmd);
        return json_decode($ret, true);
    }

    public static function getRoomRewardList($roomId, $gameId) {
        return self::PRE_ROOM_REWARD . $roomId . ':' . $gameId;
    }

    public static function getRoomInfo($roomId) {
        return $GLOBALS['roomInfo'][$roomId] ?: [];
    }

    public static function getRoomIdFromGameId($gameId) {
        return intval($gameId / 100000) % 1000;
    }

    public static function toDisplayFormat($amount, $unit = 'EOS') {
        return sprintf("%.4f {$unit}", round($amount / 10000, 4));
    }

    public static function toDisplayFormat2($amount, $unit = 'EOS', $keep = 4) {
        return sprintf("%.{$keep}f {$unit}", round($amount / 10000, 4));
    }

    public static function toNumber($amount) {
        $arr = explode(' ', $amount);
        return intval(floatval($arr[0]) * 10000);
    }


}