<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class IndividualTopUpController extends Controller
{
    protected $proxyConfig;
    protected $telegramConfig;

    public function __construct()
    {
        $this->proxyConfig = config('services.proxy');
        $this->telegramConfig = config('services.telegram');
    }

    public function TopUp(Request $request, $retryCount = 1){
       // dd($request);
        $maxRetries = 3;

        $otp = $this->generate($request->fa_key);
        $item_id = $request->item_id;
        $shell_code = $request->shell_code;
    
        $player_session = $this->GetSessionKeyFromHeader($request->player_id);
        // dd('stop');
        Log::error("Attempt: $retryCount, Player session: " . ($player_session['session_key'] ?: 'None'));
    
        if (!$player_session['session_key']) {

            $transaction = [
                'playerId' => $request->player_id,
                'playerName' => $request->player_name ?? 'Unknown',
                'packageName' => $request->packageName ?? ''
            ];
    
            $response_data = [
                'result' => 'Failed to get session key'
            ];

            $this->SendTelegramMessage($transaction, $response_data, $item_id);

            return response()->json(['status' => 'failed', 'message' => 'Failed to get session key'], 400);
        }
        else 
        {
            $response = $this->PrepairTopUpHeader($player_session, $otp, $item_id, $shell_code, $request);

            if (isset($response['response']['result']) && $response['response']['result'] == "error_2sa_otp") {
                Log::error("OTP validation failed. Retrying... Attempt: $retryCount");
                if ($retryCount < $maxRetries) {
                    return $this->TopUp($request, $retryCount + 1);
                } else {
                    Log::error("Failed to validate OTP after $maxRetries attempts.");
                    return response()->json(['status' => 'failed', 'message' => 'OTP validation failed after maximum retries.'], 400);
                }
            }
        
            Log::info("OTP validation successful on attempt $retryCount.");
            return response()->json(['status' => 'success', 'data' => $response]);
        }
    }

    private function PrepairRequestHeader($url, $data, $extraCookies = [], $ch=NULL){
        $headers = [
            "Accept: application/json, text/plain, */*",
            "Accept-Encoding: gzip, deflate, br, zstd",
            "Accept-Language: en-US,en;q=0.9",
            "Cache-Control: no-cache",
            "Connection: keep-alive",
            "Host: shop.garena.my",
            "Origin: https://shop.garena.my",
            "Pragma: no-cache",
            "Referer: https://shop.garena.my/?app=100067",
            "Sec-Fetch-Dest: empty",
            "Sec-Fetch-Mode: cors",
            "Sec-Fetch-Site: same-origin",
            "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
            'sec-ch-ua: "Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"',
            'sec-ch-ua-mobile: ?0',
            'sec-ch-ua-platform: "Windows"',
        ];
    
        $cookieString = "region=MY; mspid2=21050f7f0f41a03a2d397ba38fd59b99; _ga=GA1.1.1336503474.1730033074; language=en; _csrf=5d0AH6addsE690MkHWwpKjiF2CQXb0bA;";
    
        foreach ($extraCookies as $key => $value) {
            $cookieString .= " $key=$value;";
        }
    
        $headers[] = "Cookie: " . $cookieString;

        if (!$ch) {
            $ch = curl_init();
        
            $proxyConfig = [

                'url'      => 'my.decodo.com',
                'port'     => 30000,
                'user'     => 'spgrr83ww5',
                'password' => 'i2=Ulk9Gf3asdvh9UJ'

                // 'url'      => 'gate.decodo.com',
                // 'port'     => 7000,
                // 'user'     => 'user-spgrr83ww5-asn-55430',
                // 'password' => 'i2=Ulk9Gf3asdvh9UJ'

                // 'url'      => 'portal.anyip.io',
                // 'port'     => 1080,
                // 'user'     => 'user_820e6e,type_residential,asn_38322,sesstime_1,session_randSession4345',
                // 'password' => 'bcfc2a'

                // 'url'      => 'my.decodo.com',
                // 'port'     => 30000,
                // 'user'     => 'spxl1r7tum',
                // 'password' => 'E7=UYtct3zbX4ug0lu'

                // 'url'      => 'isp.decodo.com',
                // 'port'     => 10000,
                // 'user'     => 'user-sp5f86c6ak-country-fr',
                // 'password' => 'lnv1Sh=i8kl90RXApn'

                // 'url'      => 'gate.decodo.com',
                // 'port'     => 7000,
                // 'user'     => 'user-spxl1r7tum-country-lk',
                // 'password' => 'E7=UYtct3zbX4ug0lu'

                // 'url'      => 'la.residential.rayobyte.com',
                // 'port'     => 8000,
                // 'user'     => 'sandundilakshan700_gmail_com',
                // 'password' => 'Ttharu2001'

                // 'url'      => 'my.decodo.com',
                // 'port'     => 30001,
                // 'user'     => 'user-spxl1r7tum-sessionduration-1',
                // 'password' => 'E7=UYtct3zbX4ug0lu'
            ];
        
            $proxyUserPwd = $proxyConfig['user'] . ":" . $proxyConfig['password'];
        
            $options = [
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_POST           => true,
                CURLOPT_POSTFIELDS     => json_encode($data),
                CURLOPT_HTTPHEADER     => $headers,
                CURLOPT_HEADER         => true,
                CURLOPT_FOLLOWLOCATION => false,
                CURLOPT_PROXY          => $proxyConfig['url'],
                CURLOPT_PROXYPORT      => $proxyConfig['port'],
                CURLOPT_PROXYUSERPWD   => $proxyUserPwd
            ];
        
            curl_setopt_array($ch, $options);
        }
        
        curl_setopt($ch, CURLOPT_URL, $url);
        return $ch;        
        
    }

    public function GetSessionKeyFromHeader($playerId){
        if (!$playerId) {
            return ['error' => 'No player_id provided'];
        }
    
        $url = "https://shop.garena.my/api/auth/player_id_login";
        $payload = ["app_id" => 100067, "login_id" => $playerId];
    
        list($datadome, $session_key) = $this->RetryRequest($url, $payload);
    
        $maxRetries = 5;
        $retries = 0;
        while ($session_key === null && $retries < $maxRetries) {
            list($datadome, $session_key) = $this->RetryRequest($url, $payload);
            $retries++;
        }
        // Log::info("Retry session key attempt $retries. - $session_key - $datadome");
        Log::info("Retry session key attempt $retries. player-id - $playerId - $session_key - $datadome");
        return [
            'datadome' => $datadome ?? 'Not found',
            'session_key' => $session_key ?? 'Not found'
        ];
    }

    private function RetryRequest($url, $payload, $maxRetries = 3){
        $attempt = 0;
        $datadome = null;
        $session_key = null;
    
        while ($attempt < $maxRetries) {
            $requests = [
                ['url' => $url, 'data' => $payload, 'cookies' => []]
            ];
    
            $responses = $this->MultiRequest($requests);
            $cookies = $responses[0]['cookies'];

            $datadome = $cookies['datadome'] ?? null;
    
            if ($datadome) {
                $this->SetResponseCookie('datadome', $datadome);
    
                $requests[] = [
                    'url' => $url,
                    'data' => $payload,
                    'cookies' => ['datadome' => $datadome]
                ];
    
                $responses = $this->MultiRequest($requests);
                $cookies = $responses[1]['cookies'];
    
                $session_key = $cookies['session_key'] ?? null;
    
                if ($datadome && $session_key) {
                    break;
                }
            }

            $attempt++;
            sleep(1);
        }

        return [$datadome, $session_key];
    }

    function SetResponseCookie($name, $value) {
        if ($value) {
            header("Set-Cookie: $name=$value; Path=/; Domain=shop.garena.my; Secure; HttpOnly", false);
        }
    }

    private function MultiRequest($requests) {
        $mh = curl_multi_init();
        $channels = [];
    
        foreach ($requests as $key => $request) {
            $ch = $this->PrepairRequestHeader($request['url'], $request['data'], $request['cookies'], null);
            curl_multi_add_handle($mh, $ch);
            $channels[$key] = $ch;
        }
    
        do {
            $status = curl_multi_exec($mh, $active);
            if ($active) {
                curl_multi_select($mh);
            }
        } while ($active && $status == CURLM_OK);
    
        $responses = [];
        foreach ($channels as $key => $ch) {
            $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
            $headers = explode("\r\n", substr(curl_multi_getcontent($ch), 0, $headerSize));
            $body = substr(curl_multi_getcontent($ch), $headerSize);
            $cookies = $this->GetCookiesFromHeaders($headers);
    
            $responses[$key] = [
                'headers' => $headers,
                'body' => json_decode($body, true),
                'cookies' => $cookies
            ];
    
            curl_multi_remove_handle($mh, $ch);
        }
    
        curl_multi_close($mh);
    
        return $responses;
    }

    function GetCookiesFromHeaders($headers) {
        $cookies = [];
        foreach ($headers as $header) {
            if (preg_match_all('/Set-Cookie:\s*([^;]+)/', $header, $matches)) {
                foreach ($matches[1] as $cookie) {
                    $cookieParts = explode('=', $cookie, 2);
                    if (count($cookieParts) === 2) {
                        $cookies[trim($cookieParts[0])] = trim($cookieParts[1]);
                    }
                }
            }
        }
        return $cookies;
    }

    function TopUpCurl($url, $headers, $data, $request, $key='', $item_id) {

        $ch = curl_init($url);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

        $response = curl_exec($ch);

        if (curl_errno($ch)) {
            $error = 'Request Error: ' . curl_error($ch);
            curl_close($ch);
            return ['error' => $error];
        } else {
            $response_data = json_decode($response, true);
            $this->SendTelegramMessage($request, $response_data, $key, $item_id);
            curl_close($ch);
            return ['response' => $response_data];
        }
    }
    
    public function PrepairTopUpHeader($player_session, $otp, $item_id,$shell_code, $request){
        $url = "https://shop.garena.my/api/shop/pay/init?language=en&region=MY";

        $data = [
            "service" => "pc",
            "app_id" => 100067,
            "packed_role_id" => 0,
            "channel_id" => 202070,
            "item_id" => (int) $item_id,
            "channel_data" => [
                "otp_code" => "$otp",
                "garena_uid" => (int) $shell_code,
            ],
            "player_id" => null,
        ];
        
        $headers = [
            "Accept-Language: en-US,en;q=0.9",
            'Connection: keep-alive',
            'Content-Length: ' . strlen(json_encode($data)),
            "Cookie: source=pc; mspid2=21050f7f0f41a03a2d397ba38fd59b99; __csrf__=P59x50ixmoSlnUZotPT9Zrser2Z7g3xo;session_key=".$player_session['session_key'],
            'Host: shop.garena.my',
            'Origin: https://shop.garena.my',
            'Referer: https://shop.garena.my/app/100067/buy/0?target_channel_id=202070',
            'Sec-Fetch-Dest: empty',
            'Sec-Fetch-Mode: cors',
            'Sec-Fetch-Site: same-origin',
            'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36',
            'accept: application/json',
            'content-type: application/json',
            'sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"',
            'sec-ch-ua-mobile: ?0',
            'sec-ch-ua-platform: "Windows"',
            'x-csrf-token:P59x50ixmoSlnUZotPT9Zrser2Z7g3xo',
            'x-datadome-clientid: '.$player_session['datadome']
        ];

        return $this->MakeTopUp($url, $headers, $data, $request, $item_id);
    }

    function MakeTopUp($url, $headers, $data, $request, $item_id){
        $maxRetries = 3;
        $attempt = 0;

        //while ($attempt < $maxRetries) {
            $ch = curl_init($url);
            $otp = $this->generate($request->fa_key);
            $data['channel_data']['otp_code'] = $otp;
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

            // Set connection timeout (max time to connect)
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8);
            // Set total timeout (max time for whole request)

            curl_setopt($ch, CURLOPT_TIMEOUT, 8);

            $response = curl_exec($ch);

            if (curl_errno($ch)) {
                //$errorCode = curl_errno($ch);
                $error = 'Request Error: ' . curl_error($ch);
                Log::warning("TIMEOUT or CONNECTION ERROR ", ['error' => $error]);
                curl_close($ch);
                // Retry on connection failure or timeout errors
                // if ($errorCode === CURLE_COULDNT_CONNECT || $errorCode === CURLE_OPERATION_TIMEDOUT) {
                //     $attempt++;
                //     Log::warning("Retrying attempt number: {$attempt}");
                //     continue;
                // } else {
                //     $error = 'Request Error: ' . curl_error($ch);
                //     Log::error('Garena API Error', ['response' =>  $error ]);
                //     curl_close($ch);
                //     return ['error' => $error];
                // }
            } else {
                // Success: decode and send message
                $response_data = json_decode($response, true);
                $this->SendTelegramMessage($request, $response_data, $item_id);
                curl_close($ch);
                return ['response' => $response_data];
            }
        //}
    }

    function SendTelegramMessage($transaction, $response_data, $item_id){
        $message = '';

        if(isset($response_data['result']) && $response_data['result'] == "success"){
            $message .= "Order Completed Successfully✅\n";
        }else{
            $message .= "Order Unsuccessfully❌\n";
        }
        $message .= "UID: {$transaction['player_id']}\n";
        $message .= "Name: {$transaction['playerName']}\n";
        if($transaction['packageName']){
            $message .= "Package: {$transaction['packageName']}-{$item_id}";
        }else{
            $message .= "Package: {$item_id}";
        }
        $message .= "\nStatus:".($response_data['result'] ?? 'Session is over. Please topup this manually')."\n";
        $message .= "\nThank you for your purchase!";

        try {
            $baseUrl =  "https://api.telegram.org/bot" . $this->telegramConfig['token']. "/";
            $response = Http::post("{$baseUrl}sendMessage", [
                'chat_id' => $this->telegramConfig['chanel'],
                'text'    => $message,
            ]);

            if ($response->successful()) {
                echo $message . PHP_EOL;
                echo 'success' . PHP_EOL;
                return true;
            } else {
                echo $response->body() . PHP_EOL;
                return false;
            }
        } catch (\Exception $e) {
            echo $e->getMessage() . PHP_EOL;
            return false;
        }
    }

    public function generate($secret, $epoch = null) {
        $key = $this->base32tohex($secret);

        if (strlen($key) % 2 !== 0) {
            $key .= '0';
        }

        if ($epoch === null) {
            $epoch = round(microtime(true));
        }

        $time = $this->leftpad(dechex(floor($epoch / 30)), 16, '0');

        $hmac = hash_hmac('sha1', hex2bin($time), hex2bin($key), true);

        $offset = ord(substr($hmac, -1)) & 0xf;

        $binary = (ord($hmac[$offset]) & 0x7f) << 24 |
                  (ord($hmac[$offset + 1]) & 0xff) << 16 |
                  (ord($hmac[$offset + 2]) & 0xff) << 8 |
                  (ord($hmac[$offset + 3]) & 0xff);

        $otp = $binary % 1000000;

        return str_pad($otp, 6, '0', STR_PAD_LEFT);
    }

    private function base32tohex($base32) {
        $base32chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
        $bits = '';

        foreach (str_split($base32) as $char) {
            $val = strpos($base32chars, $char);
            $bits .= str_pad(decbin($val), 5, '0', STR_PAD_LEFT);
        }

        $hex = '';
        foreach (str_split($bits, 4) as $chunk) {
            $hex .= dechex(bindec($chunk));
        }

        return $hex;
    }

    private function leftpad($string, $length, $pad) {
        return str_pad($string, $length, $pad, STR_PAD_LEFT);
    }
}
