<?php

namespace App\Services;

use App\Models\Transaction;
use App\Support\SiteCredentialResolver;
use Illuminate\Support\Facades\Http;

class PayGarantiService
{
    protected function buildHttpClient(int $timeout, ?string $url = null)
    {
        $effectiveTimeout = max(20, $timeout);
        $connectTimeout = $effectiveTimeout;
        $curlOptions = [];
        if (defined('CURLOPT_IPRESOLVE') && defined('CURL_IPRESOLVE_V4')) {
            $curlOptions[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
        }
        if (defined('CURLOPT_DNS_CACHE_TIMEOUT')) {
            $curlOptions[CURLOPT_DNS_CACHE_TIMEOUT] = 300;
        }
        $resolveEntry = $url ? $this->buildCurlResolveEntry($url) : null;
        if ($resolveEntry && defined('CURLOPT_RESOLVE')) {
            $curlOptions[CURLOPT_RESOLVE] = [$resolveEntry];
        }

        $options = [
            'connect_timeout' => $connectTimeout,
            'force_ip_resolve' => 'v4',
        ];
        if (!empty($curlOptions)) {
            $options['curl'] = $curlOptions;
        }

        $request = Http::withOptions($options)
            ->timeout($effectiveTimeout);

        if (method_exists(\Illuminate\Http\Client\PendingRequest::class, 'retry')) {
            $request = $request->retry(3, 500);
        }

        return $request;
    }

    protected function buildCurlResolveEntry(string $url): ?string
    {
        $parts = @parse_url($url);
        if (!$parts || empty($parts['host'])) {
            return null;
        }

        $host = (string) $parts['host'];
        $scheme = strtolower((string) ($parts['scheme'] ?? 'https'));
        $port = isset($parts['port'])
            ? (int) $parts['port']
            : ($scheme === 'http' ? 80 : 443);

        $ip = @gethostbyname($host);
        if (!$ip || $ip === $host || !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return null;
        }

        return "{$host}:{$port}:{$ip}";
    }

    public function isConfigured(?Transaction $transaction = null): bool
    {
        if (!$transaction) {
            return false;
        }

        $config = $this->getConfig($transaction);

        return (bool) ($config['sid'] && $config['key'] && $config['secret']);
    }

    public function verifyDepositHash(array $data, ?string $secret = null): bool
    {
        $secret = (string) $secret;
        if ($secret === '') {
            return false;
        }

        $raw = "{$data['sid']}|{$data['key']}|{$data['amount']}|{$data['transaction_id']}|{$data['trx']}";
        $expected = base64_encode(hash_hmac('sha256', $raw, $secret, true));

        return hash_equals($expected, (string) $data['hash']);
    }

    public function verifyWithdrawHash(array $data, ?string $secret = null): bool
    {
        $secret = (string) $secret;
        if ($secret === '') {
            return false;
        }

        $name = $data['name'] ?? '';
        $iban = $data['iban'] ?? '';
        $raw = "{$data['sid']}|{$data['key']}|{$data['trx']}|{$data['amount']}|{$name}|{$iban}";
        $expected = base64_encode(hash_hmac('sha256', $raw, $secret, true));

        return hash_equals($expected, (string) $data['hash']);
    }

    public function sendWithdraw(Transaction $withdrawal): array
    {
        $config = $this->getConfig($withdrawal);
        $sid = $config['sid'];
        $key = $config['key'];
        $secret = $config['secret'];
        $url = $config['withdraw_url'];
        $notifyUrl = $config['notify_url'];
        $timeout = $config['timeout'];

        if (!$sid || !$key || !$secret || !$url || !$notifyUrl) {
            return [
                'success' => false,
                'message' => 'PayGaranti settings are incomplete.',
            ];
        }

        $amount = (int) round(((float) $withdrawal->amount) * 100);
        $trx = $withdrawal->merchant_trx_id ?: $withdrawal->transaction_id;
        $name = $withdrawal->customer_account_holder ?: ($withdrawal->customer_name ?: trim(implode(' ', array_filter([
            $withdrawal->customer_name,
            $withdrawal->customer_middle_name,
            $withdrawal->customer_surname,
        ]))));
        $iban = $withdrawal->customer_iban;
        $bankName = $withdrawal->customer_bank_name ?: 'TAG';
        $tc = $withdrawal->customer_tc ?: '00000000000';

        if (!$name || !$iban) {
            return [
                'success' => false,
                'message' => 'Missing required withdrawal fields (name, iban).',
            ];
        }

        $hashRaw = "{$sid}|{$key}|{$trx}|{$amount}|{$name}|{$iban}";
        $hash = base64_encode(hash_hmac('sha256', $hashRaw, $secret, true));

        $payload = [
            'sid' => $sid,
            'key' => $key,
            'amount' => $amount,
            'currency' => $withdrawal->currency ?: 'TRY',
            'name' => $name,
            'iban' => $iban,
            'bank_name' => $bankName,
            'tc' => $tc,
            'trx' => $trx,
            'notify_url' => $notifyUrl,
            'hash' => $hash,
        ];

        try {
            $response = $this->buildHttpClient($timeout, $url)->post($url, $payload);
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage(),
            ];
        }

        if (!$response->successful()) {
            return [
                'success' => false,
                'message' => $response->body(),
                'status' => $response->status(),
            ];
        }

        return [
            'success' => true,
            'payload' => $payload,
            'response' => $response->json(),
        ];
    }

    public function sendDepositCallback(Transaction $deposit): array
    {
        $config = $this->getConfig($deposit);
        $sid = $config['sid'];
        $key = $config['key'];
        $secret = $config['secret'];
        $url = $config['deposit_callback_url'];
        $timeout = $config['timeout'];

        if (!$sid || !$key || !$secret || !$url) {
            return [
                'success' => false,
                'message' => 'PayGaranti settings are incomplete.',
            ];
        }

        $amount = (int) round((float) $deposit->amount);
        $trx = $deposit->merchant_trx_id ?: ($deposit->customer_player_id ?: $deposit->transaction_id);
        $transactionId = $deposit->transaction_id;

        $hashRaw = "{$sid}|{$key}|{$amount}|{$transactionId}|{$trx}";
        $hash = base64_encode(hash_hmac('sha256', $hashRaw, $secret, true));

        $payload = [
            'sid' => $sid,
            'key' => $key,
            'amount' => $amount,
            'currency' => $deposit->currency ?: 'TRY',
            'transaction_id' => $transactionId,
            'status' => 1,
            'trx' => $trx,
            'player_id' => $deposit->customer_player_id,
            'hash' => $hash,
        ];

        try {
            $response = $this->buildHttpClient($timeout, $url)
                ->acceptJson()
                ->asJson()
                ->post($url, $payload);
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage(),
            ];
        }

        if (!$response->successful()) {
            return [
                'success' => false,
                'message' => $response->body(),
                'status' => $response->status(),
            ];
        }

        return [
            'success' => true,
            'payload' => $payload,
            'response' => $response->json(),
        ];
    }

    protected function getConfig(?Transaction $transaction = null): array
    {
        $timeout = 20;
        $emptyConfig = [
            'sid' => '',
            'key' => '',
            'secret' => '',
            'withdraw_url' => '',
            'notify_url' => '',
            'deposit_callback_url' => '',
            'timeout' => $timeout,
            'site_id' => null,
        ];

        if (!$transaction) {
            return $emptyConfig;
        }

        $site = SiteCredentialResolver::resolveForTransaction($transaction);
        if (!$site || !$site->is_active) {
            return $emptyConfig;
        }

        $sid = (string) ($site->sid ?? '');
        $key = (string) ($site->api_key ?? '');
        $secret = (string) ($site->secret_key ?? '');

        if ($sid === '' || $key === '' || $secret === '') {
            return $emptyConfig;
        }

        return [
            'sid' => $sid,
            'key' => $key,
            'secret' => $secret,
            'withdraw_url' => (string) ($site->withdraw_url ?? ''),
            'notify_url' => (string) ($site->notify_url ?? ''),
            'deposit_callback_url' => (string) ($site->deposit_callback_url ?? ''),
            'timeout' => $timeout,
            'site_id' => $site->id,
        ];
    }
}
