<?php

namespace App\Helpers;

use Mdanter\Ecc\EccFactory;
use Mdanter\Ecc\Random\RandomGeneratorFactory;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Crypt;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;
use TronTool\Credential;
use TronTool\TronApi;
use TronTool\TronKit;
use kornrunner\Secp256k1;
use kornrunner\Keccak;
use App\Helpers\TronRawSerializer;
use App\Http\Controllers\admin\Balance;
use kornrunner\Signature\Signature;
use Elliptic\EC;
use kornrunner\Serializer\HexSignatureSerializer;


class TronHelper
{
    public static $isTest = true;
    public static $tronUrl = 'https://api.trongrid.io';
    public static $nileUrl = 'https://nile.trongrid.io'; // 测试网

    const CONFIRMED_NUMBER = 3; // 确认数
    const GLOBAL_TRON_RATE_LIMIT_KEY = 'tron_request_global_rate_limit';
    const GLOBAL_TRON_RATE_LIMIT_SECONDS = 1;
    const TRC20_TRANSFER_TOPIC = 'ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

    protected static $client;

    public static function init()
    {

       
        if(self::getTronNetwork()){
            $url = self::$nileUrl;
        }else{
            $url = self::$tronUrl;
        }
        if (!self::$client) {
            $headers = self::getTronRequestHeaders();
            self::$client = new Client([
                'base_uri' => $url,
                'timeout'  => 10.0,
                'headers'  => $headers,
                'verify' => false
            ]);
        }
    }

    public static function getTronRequestHeaders(): array
    {
        $headers = [
            'Accept' => 'application/json',
            'Content-Type' => 'application/json',
        ];

        $apiKey = self::getTronProApiKey();
        if ($apiKey) {
            $headers['TRON-PRO-API-KEY'] = $apiKey;
        }

        return $headers;
    }

    public static function getTronProApiKey(): string
    {
        return trim((string) config('app.tron_pro_api_key', ''));
    }

    public static function getUsdtTransferFeeLimitTrx(): float
    {
        $value = (float) config('app.tron_usdt_transfer_fee_limit', 30);
        return $value > 0 ? $value : 30.0;
    }

    public static function getUsdtTransferFeeLimitSun(): int
    {
        return (int) round(self::getUsdtTransferFeeLimitTrx() * 1000000);
    }

    public static function throttleTronRequest(int $seconds = self::GLOBAL_TRON_RATE_LIMIT_SECONDS, string $key = self::GLOBAL_TRON_RATE_LIMIT_KEY): void
    {
        $store = self::getTronRateLimitStore();
        $deadline = microtime(true) + max(3, $seconds + 2);

        while (!$store->add($key, microtime(true), $seconds)) {
            usleep(200000);
            if (microtime(true) >= $deadline) {
                break;
            }
        }
    }

    protected static function getTronRateLimitStore()
    {
        try {
            return Cache::store('redis');
        } catch (\Throwable $e) {
            return Cache::store(config('cache.default'));
        }
    }

    /**
     * @description: 获取网络
     * @return {*}
     */    
    public static function getTronNetwork()
    {
        $netWork = config('app.tron_network'); // 默认是主网
        if($netWork == 'main'){
            return false;
        }else{
            return true;
        }
    }

    /**
     * @description: 创建钱包地址和私钥
     * @return {private_key,address} 
     */    
    public static function createAddress($memberId = ''): array
    {
         // 生成 TRC20 私钥
        $privateKey = self::makePrivateKey($memberId); // 默认不带 memberId
        
        // 从私钥生成地址
        $address = self::getAddressByPrivateKey($privateKey);
        
         // 记录日志
        Log::channel('wallet')->info('创建钱包地址', [
            'member_id' => $memberId,
            'address' => $address,
            'private_key' => $privateKey,
        ]);
        return [
            'address' => $address,
            'private_key' => $privateKey,
        ];

    }


    /**
     * @description: 转账USDT
     * @param {*} $privateKey   转账秘钥
     * @param {*} $toAddress    接收地址
     * @param {*} $amount       转账金额
     * @return {*}
     */    
    public static function transferUSDT($privateKey, $toAddress, $amount)
    {
        self::throttleTronRequest();

        $nodeScript = base_path('node/index.js'); // Laravel根目录下的路径
        $nodeBin = 'node'; // 用 which node 查看，或自定义
        if(self::getTronNetwork()){
            $fullNodeUrl = self::$nileUrl;
        }else{
            $fullNodeUrl = self::$tronUrl;
        }
        $contractAddress = self::getContractAddress('USDT');
        $apiKey = self::getTronProApiKey();
        $feeLimitSun = self::getUsdtTransferFeeLimitSun();
        $parts = [
            escapeshellcmd($nodeBin),
            escapeshellarg($nodeScript),
            escapeshellarg($privateKey),
            escapeshellarg($toAddress),
            escapeshellarg($contractAddress),
            escapeshellarg($fullNodeUrl),
            escapeshellarg($amount),
            escapeshellarg($feeLimitSun),
        ];
        if ($apiKey !== '') {
            $parts[] = escapeshellarg($apiKey);
        }
        $cmd = implode(' ', $parts) . ' 2>&1';

        exec($cmd, $outputLines, $status);
        $output = implode("\n", $outputLines);
        $result = json_decode($output, true);
        return $result;
        // self::init();

        // $contractAddress = self::getContractAddress('USDT');

        // $fromAddress = self::getAddressByPrivateKey($privateKey);
        

        // // 1. 构建转账交易
        // $transferData = [
        //     'owner_address'     => self::base58check2HexString($fromAddress),
        //     'contract_address'  => self::base58check2HexString($contractAddress),
        //     'function_selector' => 'transfer(address,uint256)',
        //     'parameter'         => self::buildParameter($toAddress, $amount),
        //     'visible'           => false
        // ];
   
        
       
        // $response = self::$client->post('/wallet/triggersmartcontract', [
        //     'json' => $transferData
        // ]);
        // $data = json_decode($response->getBody(), true);
        // var_dump($data);

 
        // if (empty($data['transaction'])) {
        //     throw new \Exception('构建转账交易失败: ' . json_encode($data));
        // }

        // $txid = $data['transaction']['txID'];
        
        // // 2. 签名交易
        // // $rawData = $data['transaction']['raw_data'];
        // // $rawDataBytes = TronRawSerializer::serializeRawData($rawData); // 自定义函数，返回 Protobuf 序列化后的二进制
        // // $txHash = hash('sha256', $rawDataBytes); // Tron使用 SHA256，不是 Keccak256
        // // // 使用私钥签名
        // // $secp256k1 = new Secp256k1();
        // // $signature = $secp256k1->sign($txHash, $privateKey);
        // // $signatureHex = self::formatTronSignature($signature);

        // $signedTx = self::signTronTransaction($data['transaction'],$privateKey);
        // // var_dump($signatureHex);
        
        // // $signedTx['visible'] = true;
        // // 3. 广播交易
        // // 将 signature 转成 hex 字符串
        // // $signatureHex = bin2hex($signature);
        // // $signatureHex = $signature;
        // // var_dump($signatureHex);
        // // 构建签名交易
        // // $signedTx = [
        // //     'txID'     => $data['transaction']['txID'],
        // //     'raw_data' => $data['transaction']['raw_data'],
        // //     'signature' => $signatureHex,
        // // ];
        // var_dump($signedTx);
        // $broadcast = self::$client->post('/wallet/broadcasttransaction', [
        //     'json' => $signedTx
        // ]);
        // $broadcastData = json_decode($broadcast->getBody(), true);

        // return $broadcastData;
    }

    public static function signTronTransaction(array $transaction, string $privateKey): array
    {
        $rawData = $transaction['raw_data'] ?? null;
        if (!$rawData) {
            throw new \Exception('交易中没有 raw_data');
        }

        $rawDataBytes = TronRawSerializer::serializeRawData($rawData); 

        $txHash = hash('sha256', $rawDataBytes, true); // 二进制哈希

        $privateKeyHex = ltrim($privateKey, '0x');
        if (strlen($privateKeyHex) !== 64) {
            throw new \Exception('私钥格式不正确');
        }
        $privateKeyBin = hex2bin($privateKeyHex);

        $secp256k1 = new Secp256k1();
        $signatureObj = $secp256k1->sign($txHash, $privateKeyBin);

        // r, s 都是 GMP 对象，转成32字节二进制字符串
        $rBin = self::gmpToBin32($signatureObj->getR());
        $sBin = self::gmpToBin32($signatureObj->getS());

        $signatureBin = $rBin . $sBin; // 64字节二进制签名

        $transaction['signature'] = [$signatureBin];

        return $transaction;
    }

    private static function gmpToBin32($gmpNum): string
    {
        $hex = gmp_strval($gmpNum, 16);
        if (strlen($hex) % 2 !== 0) {
            $hex = '0' . $hex;
        }
        $bin = hex2bin($hex);
        return str_pad($bin, 32, "\0", STR_PAD_LEFT);
    }

    /**
     * 构建 parameter 字符串（目标地址 + 金额）
     */
    protected static function buildParameter($toAddress, $amount)
    {
        $hexAddress = self::base58check2HexString($toAddress);
        $addr = str_pad(substr($hexAddress, 2), 64, '0', STR_PAD_LEFT); // 去掉 '41' 开头的 Tron 前缀
        $amt  = str_pad(bcdechex(bcmul($amount, '1000000')), 64, '0', STR_PAD_LEFT); // USDT 精度 6

        return $addr . $amt;
    }


    // /**
    //  * @param Signature $signature
    //  * @return string 65字节签名的十六进制字符串
    //  */
    // public static function formatTronSignature(Signature $signature): string
    // {
    //     $r = gmp_strval($signature->getR(), 16);
    //     $s = gmp_strval($signature->getS(), 16);
    //     $v = dechex($signature->getRecoveryParam()); // v 即 recoveryParam

    //     // 补齐 r 和 s 为 64位长度（即32字节）
    //     $r = str_pad($r, 64, '0', STR_PAD_LEFT);
    //     $s = str_pad($s, 64, '0', STR_PAD_LEFT);
    //     $v = str_pad($v, 2, '0', STR_PAD_LEFT); // 1字节 = 2个hex字符
      
    //     $v_decimal = hexdec($v); // 0
    //     $v_decimal += 27;        // 27
    //     $v_hex = dechex($v_decimal); // "1b"
    //     return $r . $s . $v_hex; // 返回最终的签名字符串
    // }

    /**
     * @description: 获取地址的YRX余额
     * @param {*} $addressBase58
     * @return {*}
     */    
    public static function getTrxBalance($addressBase58)
    {
        self::throttleTronRequest();

        $hexAddress = TronHelper::base58check2HexString($addressBase58);
        
        self::init();

        $response = self::$client->post('/wallet/getaccount', [
            'json' => ['address' => $hexAddress]
        ]);

        $data = json_decode($response->getBody(), true);
        
        if (!empty($data['balance'])) {
            // TRX 的单位是 sun，1 TRX = 1_000_000 sun
            return $data['balance'] / 1_000_000;
        }

        return 0;
    }

    // /**
    //  * @description: 向账户转TRX能量
    //  * @param {*} $fromAddress
    //  * @param {*} $privateKey
    //  * @param {*} $toAddress
    //  * @param {*} $amount
    //  * @return {*}
    //  */    
    // public static function transferTRX($fromAddress, $privateKey, $toAddress, $amount)
    // {
    //     self::init();

    //     $ownerAddressHex = self::base58check2HexString($fromAddress);
    //     $toAddressHex = self::base58check2HexString($toAddress);

    //     $createData = [
    //         'owner_address' => $ownerAddressHex,
    //         'to_address' => $toAddressHex,
    //         'amount' => (int)($amount * 1_000_000), // TRX 精度为 6
    //     ];

        
    //     // 构建转账交易
    //     $response = self::$client->post('/wallet/createtransaction', [
    //         'json' => $createData
    //     ]);

    //     $tx = json_decode($response->getBody(), true);
       
    //     if (!isset($tx['txID'])) {
    //         throw new \Exception('创建转账交易失败: ' . json_encode($tx));
    //     }
   

    //     // 签名交易
    //     $signature = self::signTransaction($tx,$privateKey);

    //     // 广播交易
    //     $signedTx = [
    //         'txID'     => $tx['txID'],
    //         'raw_data' => $tx['raw_data'],
    //         'raw_data_hex' => $tx['raw_data_hex'],
    //         'signature' => $signature,
    //     ];


    //     $response = self::$client->post('/wallet/broadcasttransaction', [
    //         'json' => $signedTx
    //     ]);

    //     var_dump($signedTx);


    //     $result = json_decode($response->getBody(), true);
    //     var_dump($result);
    //     die();
    //     // if (!isset($result['result']) || !$result['result']) {
    //     //     throw new \Exception('广播失败: ' . json_encode($result));
    //     // }

    //     return [
    //         'txID' => $tx['txID'],
    //         'result' => true
    //     ];
    // }

    // /**
    //  * @description: TRX签名
    //  * @param {array} $transaction
    //  * @param {string} $privateKey
    //  * @return {*}
    //  */    
    // public static function signTransaction($tx, $privateKey)
    // {
    //     if (empty($tx['raw_data_hex'])) {
    //         throw new \Exception('原始交易数据为空，无法签名');
    //     }

    //     $rawDataHex = $tx['raw_data_hex'];
    //     $rawDataBin = hex2bin($rawDataHex);
    //     $hash = hash('sha256', $rawDataBin, true); // 原始数据做 SHA256

    //     $signatureDer = self::ecdsaSignRaw($hash, $privateKey); // 返回 DER 格式签名
    //     return [$signatureDer]; // Tron 要求是签名数组
    // }

    // public static function ecdsaSignRaw($hash, $privateKeyHex)
    // {
    //     $ec = new EC('secp256k1');
    //     $key = $ec->keyFromPrivate($privateKeyHex);

    //     $signature = $key->sign(bin2hex($hash), ['canonical' => true]);

    //     $r = str_pad($signature->r->toString('hex'), 64, '0', STR_PAD_LEFT);
    //     $s = str_pad($signature->s->toString('hex'), 64, '0', STR_PAD_LEFT);

    //     return hex2bin($r . $s); // 返回64字节的二进制字符串
    // }

    /**
     * 查询某地址的 TRX 充值记录
     * @param string $address 充值地址
     * @param int $limit 返回记录数
     * @return array
     */
    public static function getTrxTransactions(string $address, int $limit = 30): array
    {

        self::init();

        $response = self::$client->get("https://nile.trongrid.io/v1/accounts/{$address}/transactions", [
            'query' => [
                'limit' => $limit,
                'only_confirmed' => 'true',
                'order' => 'desc',
            ]
        ]);

        $data = json_decode($response->getBody()->getContents(), true);
        
        return $data;
    }

    /**
     * 查询某地址的 TRC20 USDT 充值记录
     * @param string $address 充值地址
     * @param int $limit 返回记录数
     * @return array
     */
    public static function getTrc20UsdtRecharges(string $address, int $limit = 30): array
    {

        self::throttleTronRequest();

        self::init();

        $usdtContract = self::getContractAddress('USDT');
        
        try {
            $response = self::$client->get("/v1/accounts/{$address}/transactions/trc20", [
                'headers' => [
                    'Accept' => 'application/json',
                ],
                'query' => [
                    'limit' => $limit,
                    'only_confirmed' => 'true',
                    'order_by' => 'block_timestamp,desc',
                ],
                'timeout' => 10,
            ]);
            $data = json_decode($response->getBody()->getContents(), true);
            

            $recharges = [];
            foreach ($data['data'] ?? [] as $item) {
                $tokenAddress = $item['token_info']['address'] ?? '';
                if (strtolower($tokenAddress) !== strtolower($usdtContract)) {
                    continue; // 不是USDT
                }

                $txid = $item['transaction_id'] ?? '';
                if (empty($txid)) {
                    continue;
                }

                $transfer = self::getUsdtTransferByTxid($txid, $address);
                if (empty($transfer['success'])) {
                    Log::warning('忽略非USDT Transfer充值记录', [
                        'address' => $address,
                        'txid' => $txid,
                        'message' => $transfer['message'] ?? '',
                    ]);
                    continue;
                }

                $recharges[] = [
                    'txid'         => $txid,
                    'from_address' => $transfer['from_address'],
                    'to_address'   => $transfer['to_address'],
                    'amount'       => $transfer['amount'],
                    'coin'         => 'USDT',
                    'block_time'   => $transfer['block_time'],
                    'block_height' => $transfer['block_number'],
                ];
            }
            return $recharges;
        } catch (\Throwable $e) {
            Log::warning('获取TRC20 USDT充值记录失败', [
                'address' => $address,
                'error' => $e->getMessage(),
            ]);
            return [];
        }
    }

    /**
     * 查询并校验单笔交易是否为打到指定地址的 USDT Transfer 事件。
     */
    public static function getUsdtTransferByTxid(string $txid, ?string $expectedToAddress = null): array
    {
        self::throttleTronRequest();

        self::init();

        try {
            $txResp = self::$client->post('/wallet/gettransactioninfobyid', [
                'json' => ['value' => $txid],
                'headers' => ['Accept' => 'application/json'],
            ]);
            $txData = json_decode($txResp->getBody()->getContents(), true);

            $result = self::parseUsdtTransferEventFromTransactionInfo($txData, $expectedToAddress);
            if (empty($result['success'])) {
                return $result;
            }

            $result['txid'] = $txid;
            return $result;
        } catch (\Throwable $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * 查询确认数，同时强制校验交易必须是 USDT Transfer。
     */
    public static function getUsdtTransferConfirmation(string $txid, ?string $expectedToAddress = null): array
    {
        $transfer = self::getUsdtTransferByTxid($txid, $expectedToAddress);
        if (empty($transfer['success'])) {
            return $transfer;
        }

        try {
            $blockResp = self::$client->get('/wallet/getnowblock', [
                'headers' => ['Accept' => 'application/json'],
            ]);
            $blockData = json_decode($blockResp->getBody()->getContents(), true);
            $latestBlock = $blockData['block_header']['raw_data']['number'] ?? 0;

            if ($latestBlock == 0) {
                return ['success' => false, 'message' => '无法获取最新区块'];
            }

            $confirmations = $latestBlock - $transfer['block_number'] + 1;

            return $transfer + [
                'latest_block' => $latestBlock,
                'confirmations' => $confirmations,
            ];
        } catch (\Throwable $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * 从 gettransactioninfobyid 返回值解析 USDT Transfer 事件。
     */
    public static function parseUsdtTransferEventFromTransactionInfo(array $txData, ?string $expectedToAddress = null, ?string $usdtContractAddress = null): array
    {
        if (empty($txData['blockNumber'])) {
            return ['success' => false, 'message' => '交易尚未被打包或无效'];
        }

        if (($txData['receipt']['result'] ?? 'SUCCESS') !== 'SUCCESS') {
            return ['success' => false, 'invalid' => true, 'message' => '交易执行失败'];
        }

        $usdtContractAddress = $usdtContractAddress ?: self::getContractAddress('USDT');
        $usdtLogAddress = self::normalizeTronLogAddress($usdtContractAddress);

        foreach ($txData['log'] ?? [] as $log) {
            $logAddress = self::normalizeTronLogAddress($log['address'] ?? '');
            if ($logAddress !== $usdtLogAddress) {
                continue;
            }

            $topics = $log['topics'] ?? [];
            if (count($topics) < 3 || self::stripHexPrefix($topics[0]) !== self::TRC20_TRANSFER_TOPIC) {
                continue;
            }

            $fromAddress = self::tronAddressFromEventTopic($topics[1]);
            $toAddress = self::tronAddressFromEventTopic($topics[2]);
            if (!$fromAddress || !$toAddress) {
                continue;
            }

            if ($expectedToAddress && !self::sameTronAddress($toAddress, $expectedToAddress)) {
                continue;
            }

            $amountRaw = self::hexToDecimalString($log['data'] ?? '0');
            if (bccomp($amountRaw, '0', 0) <= 0) {
                continue;
            }

            return [
                'success' => true,
                'from_address' => $fromAddress,
                'to_address' => $toAddress,
                'amount' => bcdiv($amountRaw, '1000000', 6),
                'amount_raw' => $amountRaw,
                'block_number' => $txData['blockNumber'],
                'block_time' => isset($txData['blockTimeStamp']) ? intval($txData['blockTimeStamp'] / 1000) : null,
            ];
        }

        return ['success' => false, 'invalid' => true, 'message' => '未找到匹配的USDT Transfer事件'];
    }

    private static function normalizeTronLogAddress(string $address): string
    {
        $address = trim($address);
        if (strlen($address) === 34 && substr($address, 0, 1) === 'T') {
            try {
                $address = self::base58check2HexString($address);
            } catch (\Throwable $e) {
                return strtolower($address);
            }
        }

        $address = self::stripHexPrefix($address);
        if (strlen($address) === 42 && substr($address, 0, 2) === '41') {
            return substr($address, 2);
        }

        return $address;
    }

    private static function tronAddressFromEventTopic(string $topic): ?string
    {
        $topic = self::stripHexPrefix($topic);
        if (strlen($topic) < 40 || !ctype_xdigit($topic)) {
            return null;
        }

        try {
            return self::hexString2Base58check('41' . substr($topic, -40));
        } catch (\Throwable $e) {
            return null;
        }
    }

    private static function sameTronAddress(string $left, string $right): bool
    {
        return trim($left) === trim($right);
    }

    private static function hexToDecimalString(string $hex): string
    {
        $hex = self::stripHexPrefix($hex);
        if ($hex === '') {
            return '0';
        }
        if (!ctype_xdigit($hex)) {
            return '0';
        }

        $decimal = '0';
        foreach (str_split($hex) as $char) {
            $decimal = bcadd(bcmul($decimal, '16', 0), (string) hexdec($char), 0);
        }

        return $decimal;
    }

    private static function stripHexPrefix(string $hex): string
    {
        $hex = strtolower(trim($hex));
        if (substr($hex, 0, 2) === '0x') {
            return substr($hex, 2);
        }

        return $hex;
    }


    /**
     * @description: 获取TRC20账户余额
     * @param {*} $address
     * @return {*}
     */    
    public static function getTrc20Balance($address)
    {
        self::throttleTronRequest();

        self::init();

        $contractAddress = self::getContractAddress('USDT');

        $hexAddress = self::base58check2HexString($address);

        $postData = [
            'owner_address'     => $hexAddress,
            'contract_address'  => self::base58check2HexString($contractAddress),
            'function_selector' => 'balanceOf(address)',
            'parameter'         => str_pad(substr($hexAddress, 2), 64, '0', STR_PAD_LEFT),
        ];

        // try {
            $response = self::$client->post('/wallet/triggerconstantcontract', [
                'headers' => [
                    'Content-Type' => 'application/json',
                ] + self::getTronRequestHeaders(),
                'json' => $postData,
            ]);

            $body = $response->getBody()->getContents();
            $data = json_decode($body, true);
            
            $hexBalance = $data['constant_result'][0] ?? '0x0';

            return hexdec($hexBalance) / 1e6; // USDT 精度是 6 位
        // } catch (\Exception $e) {
        //     // 可以记录日志或抛出异常
        //     return 0;
        // }
    }


    /**
     * 查询交易确认数
     * @param string $txid 交易哈希
     * @return array
     */
    public static function getTransactionConfirmations(string $txid): array
    {
        // $client = new Client(['timeout' => 10]);

        self::throttleTronRequest();

        self::init();

        try {
            // 1. 获取交易信息
            $txResp = self::$client->post('/wallet/gettransactioninfobyid', [
                'json' => ['value' => $txid],
                'headers' => ['Accept' => 'application/json'],
            ]);
            $txData = json_decode($txResp->getBody()->getContents(), true);

            if (!isset($txData['blockNumber'])) {
                return ['success' => false, 'message' => '交易尚未被打包或无效'];
            }

            $txBlock = $txData['blockNumber'];

            // 2. 获取最新区块高度
            $blockResp = self::$client->get('/wallet/getnowblock', [
                'headers' => ['Accept' => 'application/json'],
            ]);
            $blockData = json_decode($blockResp->getBody()->getContents(), true);
            $latestBlock = $blockData['block_header']['raw_data']['number'] ?? 0;

            if ($latestBlock == 0) {
                return ['success' => false, 'message' => '无法获取最新区块'];
            }

            // 3. 计算确认数
            $confirmations = $latestBlock - $txBlock + 1;

            return [
                'success' => true,
                'txid' => $txid,
                'block_number' => $txBlock,
                'latest_block' => $latestBlock,
                'confirmations' => $confirmations,
            ];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }


    /**
     * 加密私钥
     */
    public static function encryptPrivateKey(string $privateKeyHex): string
    {
        return Crypt::encryptString($privateKeyHex);
    }

    /**
     * 解密私钥
     */
    public static function decryptPrivateKey(string $encrypted): string
    {
        return Crypt::decryptString($encrypted);
    }

    /**
     * 获取合约地址
     * @param $currency
     * @return string
     */
    public static function getContractAddress($currency)
    {
        $currency = strtoupper($currency);
        switch ($currency) {
            case 'USDT'://usdt
                if(self::getTronNetwork()){
                    $contractAddress = 'TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf'; // nile测试地址
                }else{
                    $contractAddress = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';
                }
                break;
            case 'USDC'://usdc
                $contractAddress = 'TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8';
                break;
            case 'USDJ'://USDJ
                $contractAddress = 'TMwFHYXLJaRUPeW6421aqXL4ZEzPRFGkGT';
                break;
            case 'TUSD'://TUSD
                $contractAddress = 'TUpMhErZL2fhh4sVNULAbNKLokS4GjC1F4';
                break;
            case 'BTC'://BTC
                $contractAddress = 'TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9';
                break;
            case 'ETH'://ETH
                $contractAddress = 'THb4CqiFdwNHsWsQCs4JhzwjMWys4aqCbF';
                break;
            case 'USDD'://USDD
                $contractAddress = 'TPYmHEhy5n8TCEfYGqW2rPxsghSfzghPDn';
                break;
            default:
                $contractAddress = '';
        }

        return $contractAddress;
    }


    public static function base58_encode($string)
    {
        if (is_string($string) === false) {
            return false;
        }
        if ($string === '') {
            return '';
        }

        $alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
        $base = strlen($alphabet);

        $bytes = array_values(unpack('C*', $string));
        $decimal = $bytes[0];
        for ($i = 1, $l = count($bytes); $i < $l; $i++) {
            $decimal = bcmul($decimal, 256);
            $decimal = bcadd($decimal, $bytes[$i]);
        }
        $output = '';
        while ($decimal >= $base) {
            $div = bcdiv($decimal, $base, 0);
            $mod = bcmod($decimal, $base);
            $output .= $alphabet[$mod];
            $decimal = $div;
        }
        if ($decimal > 0) {
            $output .= $alphabet[$decimal];
        }
        $output = strrev($output);
        foreach ($bytes as $byte) {
            if ($byte === 0) {
                $output = $alphabet[0].$output;
                continue;
            }
            break;
        }

        return $output;
    }

    public static function base58_decode($base58)
    {
        if (is_string($base58) === false) {
            return false;
        }
        if ($base58 === '') {
            return '';
        }

        $alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
        $base = strlen($alphabet);

        $indexes = array_flip(str_split($alphabet));
        $chars = str_split($base58);
        foreach ($chars as $char) {
            if (isset($indexes[$char]) === false) {
                return false;
            }
        }
        $decimal = $indexes[$chars[0]];
        for ($i = 1, $l = count($chars); $i < $l; $i++) {
            $decimal = bcmul($decimal, $base);
            $decimal = bcadd($decimal, $indexes[$chars[$i]]);
        }
        $output = '';
        while ($decimal > 0) {
            $byte = bcmod($decimal, 256);
            $output = pack('C', $byte).$output;
            $decimal = bcdiv($decimal, 256, 0);
        }
        foreach ($chars as $char) {
            if ($indexes[$char] === 0) {
                $output = "\x00".$output;
                continue;
            }
            break;
        }

        return $output;
    }

//encode address from byte[] to base58check string
    public static function base58check_en($address)
    {
        $hash0 = hash("sha256", $address);
        $hash1 = hash("sha256", hex2bin($hash0));
        $checksum = substr($hash1, 0, 8);
        $address .= hex2bin($checksum);

        return self::base58_encode($address);
    }

    public static function base58check_de($base58add)
    {
        $address = self::base58_decode($base58add);
        $size = strlen($address);
        if ($size !== 25) {
            return false;
        }
        $checksum = substr($address, 21);
        $address = substr($address, 0, 21);
        $hash0 = hash("sha256", $address);
        $hash1 = hash("sha256", hex2bin($hash0));
        $checksum0 = substr($hash1, 0, 8);
        $checksum1 = bin2hex($checksum);
        if (strcmp($checksum0, $checksum1)) {
            return false;
        }

        return $address;
    }

    public static function hexString2Base58check($hexString)
    {
        $address = hex2bin($hexString);

        return self::base58check_en($address);
    }

    public static function base58check2HexString($base58add)
    {
        $address = self::base58check_de($base58add);
        return bin2hex($address);
    }

    public static function hexString2Base64($hexString)
    {
        $address = hex2bin($hexString);

        return base64_encode($address);
    }

    public static function base642HexString($base64)
    {
        $address = base64_decode($base64);

        return bin2hex($address);
    }

    public static function base58check2Base64($base58add)
    {
        $address =self::base58check_de($base58add);

        return base64_encode($address);
    }

    public static function base642Base58check($base64)
    {
        $address = base64_decode($base64);

        return self::base58check_en($address);
    }

    public static function getrandstr($length)
    {
        $str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
        $randStr = str_shuffle($str);//打乱字符串

        return substr($randStr, 0, $length);
    }

    /**
     * 检测是否有效钱包地址
     * @param $address
     * @return bool
     */
    public static function isValidAddress($address)
    {
        if (empty($address)) {
            return false;
        }
        if (strlen($address) != 34) {
            return false;
        }
        if (substr($address, 0, 1) != 'T') {
            return false;
        }
        // 验证地址
        $client = new Client([
            'verify' => false, // 关闭 SSL 验证
        ]);
        $response = $client->request('POST', 'https://api.shasta.trongrid.io/wallet/validateaddress', [
            'body' => json_encode(["address" => $address]),
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
        ]);
        $resp = $response->getBody()->getContents();
        $resp = json_decode($resp);
        // 失败提示错误
        if ($resp->result === false) {
            return false;
        }

        return true;
    }

    /**
     * 获取私钥，通过私钥可以拿到收款地址，各种权限
     * 注意：必须拿28位字符串来生成地址，否则无法生成正常的地址
     * @param $base64
     * @return string
     */
    public function getPrivateKey($base64)
    {
        return $this->base642HexString($base64);
    }

    /**
     * 生成波场key
     * @param $memberId
     * @return string
     */
    public static function makePrivateKey($memberId)
    {
        $fix = 'SSTGsstg';//固定8前缀，避免和其他人同地址
        $rand = TronHelper::getrandstr(20);//10位数随机，避免同地址
        $base64Sting = $fix.$rand.str_pad($memberId, 15, 0, STR_PAD_LEFT);
        $tronHelper = new TronHelper();
        

        return $tronHelper->getPrivateKey($base64Sting);
    }


    /**
     * 查询余额
     * @param $privateKey
     * @return int
     */
    public static function getBalance($address, $currency)
    {
        bcscale(6);
        $rate = 1000000;
        $currency = strtoupper($currency);
        if(self::getTronNetwork()){
            $api = TronApi::testNetNilo();
        }else{
            $api = TronApi::mainNet();
        }
       
        $privateKey = self::makePrivateKey(time());
        $credential = Credential::fromPrivateKey($privateKey);
       
        $kit = new TronKit($api, $credential);
       
        if ($currency == 'TRX') {
            try {
                $balance = $kit->getTrxBalance($address);
                
                return bcdiv($balance, $rate);
            } catch (\Exception $e) {
                return bcmul(0, 0);
            }
        }
        try {
            $contractAddress = self::getContractAddress($currency);
           
            $usdt = $kit->Trc20($contractAddress);

            $balance = $usdt->balanceOf($address);

            return bcdiv($balance, $rate);
        } catch (\Exception $e) {
            return bcmul(0, 0);
        }
    }

    /**
     * 获取转账信息
     * @param $txid
     */
    public static function getSendInfo($txid)
    {
        // $api = TronApi::mainNet();
        if(self::getTronNetwork()){
            $api = TronApi::testNetNilo();
        }else{
            $api = TronApi::mainNet();
        }
        $ret = $api->getTransaction($txid);
        $retArr = $ret->ret;
        if (isset($retArr[0]->contractRet)) {
            return $retArr[0]->contractRet;
        }

        return 'UNKNOWN';
    }

    /**
     * 完整交易详情，如果交易未完成或者不成功，返回空
     * @param $txid
     * @return string
     */
    public static function getTransactionInfoById($txid)
    {
        // $api = TronApi::mainNet();
        if(self::getTronNetwork()){
            $api = TronApi::testNetNilo();
        }else{
            $api = TronApi::mainNet();
        }
        $ret = $api->getTransactionInfoById($txid);

        return json_decode(json_encode($ret), true);
    }

    /**
     * 获取出款账户地址
     */
    public static function getWithdrawAddress()
    {
        // $privateKey = Yii::$app->params['withdraw_address_trx_key'];
        // $credential = Credential::fromPrivateKey($privateKey);

        // return $credential->address()->base58();
    }

    /**
     * 获取地址
     * @param $fromKey
     */
    public static function getAddressByPrivateKey($fromKey)
    {
       
        $credential = Credential::fromPrivateKey($fromKey);

        return $credential->address()->base58();
    }

    /**
     * 转账给指定地址
     * @param $fromKey
     * @param $toAddress
     * @param $amount
     * @throws \Exception
     */
    public static function sendTrx($fromKey, $toAddress, $amount)
    {
        if ($amount <= 0) {
            throw new \Exception('不能低于 0 trx');
        }
        self::throttleTronRequest();

        // from 初始化
        if(self::getTronNetwork()){
            $api = TronApi::testNetNilo();
        }else{
            $api = TronApi::mainNet();
        }
        $credential = Credential::fromPrivateKey($fromKey);
        $kit = new TronKit($api, $credential);
        // from 余额判断
        $from = $credential->address()->base58();
        $balance = self::getBalance($from, 'TRX');
        $rate = 1000000;
        if ($balance < $amount) {
            return '余额不足';
        }
        // 发送
        try {
            return $kit->sendTrx($toAddress, 1 * bcmul($amount, $rate, 6));
        } catch (\Exception $e) {
            Log::error('转账错误,fromKey='.$fromKey.'toAddress='.$toAddress.'amount='.$amount);
            Log::error('转账错误'.$e->getMessage());

            return false;
        }
    }

    /**usdt转账
     * @param $fromKey
     * @param $toAddress
     * @param $amount
     * @param $currency
     * @return bool|object
     * @throws \Exception
     */
    public static function sendTrc20($fromKey, $toAddress, $amount, $currency)
    {
        if ($amount <= 0) {
            throw new \Exception('不能低于 0 USDT');
        }
        $credential = Credential::fromPrivateKey($fromKey);
        $credential->address()->hex();

        if(self::getTronNetwork()){
            $api = TronApi::testNetNilo();
        }else{
            $api = TronApi::mainNet();
        }
        $kit = new TronKit($api, $credential);
        $contractAddress = self::getContractAddress($currency);
        $rate = 1000000;//换算汇率
        // $balance = self::getBalance(self::getAddressByPrivateKey($fromKey), $currency);  //查询Trc20代币余额
        $balance = self::getTrc20Balance(self::getAddressByPrivateKey($fromKey));  //查询Trc20代币余额
        
        
        if ($balance < $amount) {
            throw new \Exception('余额不足');
        }
    
        $trc20 = $kit->Trc20($contractAddress);                      //创建Trc20代币合约实例
        try {
            $ret = $trc20->transfer($toAddress, (int) bcmul($amount, $rate));                        //转账Trc20代币

            return (object) [
                'txid' => $ret->tx->txID,
                'result' => $ret->result,
            ];
        } catch (\Exception $e) {
            Log::error('Trc20转账错误,fromKey='.$fromKey.'toAddress='.$toAddress.'amount='.$amount);
            Log::error('Trc20转账错误'.$e->getMessage());

            return false;
        }
    }

    /**
     * 归集账户资金校验
     * trade_status：
     * - failed 转账失败
     * - waiting 转账成功，尚未校验
     * - closed waiting 之后，脚本查询时，交易验证成功
     * - aborted waiting 之后，脚本查询时，交易验证失败
     * @param $fromKey
     * @param $toAddress
     * @param $amount
     * @param $memberId
     * @param  string  $currency
     * @param  string  $net
     * @return bool
     * @throws \Exception
     */
    public function actionFundsGather(
        $fromKey,
        $toAddress,
        $amount,
        $memberId,
        $currency = 'TRX',
        $net = 'TRC20'
    ) {
        // $currency = strtoupper($currency);
        // if ($amount <= 0) {
        //     throw new \Exception('不能低于 0 trx');
        // }
        // if (empty($toAddress)) {
        //     throw new \Exception('收款地址不能为空');
        // }

        // $fromAddress = self::getAddressByPrivateKey($fromKey);
        // $remainAmount = self::getBalance($fromAddress, $currency);
        // if ($remainAmount < $amount) {
        //     throw new \Exception('余额不足，归集失败');
        // }
        // $min = MinRechargeEnum::getValue($currency);
        // if ($currency == 'TRX') {
        //     $ret = self::sendTrx($fromKey, $toAddress, $amount);
        // } else {
        //     // 发送
        //     //校验trx是否足够，不够就充值10燃烧费用进来
        //     if (self::getBalance($fromAddress, 'TRX') < 10) {
        //         $withdrawAddressTrxKey = Yii::$app->params['withdraw_address_trx_key'];
        //         self::sendTrx($withdrawAddressTrxKey, self::getAddressByPrivateKey($fromKey), 10);
        //     }
        //     $ret = self::sendTrc20($fromKey, $toAddress, $amount, $currency);
        // }

        // //少于最低可入款额度，不入账，只做归集
        // if ($min > $remainAmount) {
        //     return false;
        // }

        // try {
        //     // 记录
        //     $fundsGather = new Recharge();
        //     $fundsGather->member_id = $memberId;
        //     $fundsGather->txid = $ret->txid;
        //     $fundsGather->amount = $amount;
        //     $fundsGather->address = $toAddress;
        //     $fundsGather->created_at = time();
        //     $fundsGather->currency = $currency;
        //     $fundsGather->usdt_balance = bcmul($amount, ExchangeRateService::getExchangeRate($currency),
        //         CommonEnum::DIGITS);
        //     $fundsGather->is_auto = 1;
        //     $fundsGather->count = Recharge::find()->where(['member_id' => $memberId])->count() + 1;
        //     $fundsGather->net = $net;
        //     $fundsGather->ordernum = StrHelper::createOrdernum();

        //     // 记录「充值请求次数」
        //     $member = Member::findOne($memberId);
        //     $member->recharge_request_count = $fundsGather->count;
        //     $member->save();

        //     if ($ret->result == 1) { // 成功
        //         $fundsGather->trade_status = 'waiting';
        //         if ($fundsGather->save()) {
        //             return true;
        //         }
        //     } else { // 失败
        //         $fundsGather->trade_status = 'failed';
        //         $fundsGather->save();
        //     }
        // } catch (Exception $e) {
        //     throw new \Exception('转账异常'.$e->getMessage());
        // }

        return false;
    }

}
