<?php

namespace App\Modules\Payment\Isbank;

use App\Core\Payment\AbstractPayment;
use Illuminate\Support\Facades\Log;

class Isbank extends AbstractPayment
{
    protected $apiUrl;

    protected $gatewayUrl;

    /** EST/NestPay merchant-config-oran modeli: taksit farkini PROCP hesaplar (installment_commission). */
    protected string $installmentSurchargeMode = 'procp';

    public function __construct(array $config = [])
    {
        parent::__construct($config);

        $this->apiUrl = $this->getApiUrl();
        $this->gatewayUrl = $this->get3DGatewayUrl();
    }

    /**
     * Odeme girisimi baslatir - kart ve tutar dogrulamasi yapar
     *
     * @return array
     */
    public function attemptPayment(array $params)
    {
        $requiredParams = ['amount', 'card_number', 'exp_month', 'exp_year', 'cvv'];

        foreach ($requiredParams as $param) {
            if (! isset($params[$param]) || empty($params[$param])) {
                return [
                    'status' => 'error',
                    'message' => __('admin/modules.isbank_missing_param', ['param' => $param]),
                ];
            }
        }

        // Kart numarasi formati kontrol
        $cardNumber = preg_replace('/\s+/', '', $params['card_number']);
        if (! preg_match('/^\d{13,19}$/', $cardNumber)) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.isbank_invalid_card'),
            ];
        }

        // Luhn kontrolu
        if (! $this->luhnCheck($cardNumber)) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.isbank_invalid_card'),
            ];
        }

        // Fraud kontrol
        $fraudCheck = $this->performPreFraudCheck($params);
        if ($fraudCheck['status'] === 'error') {
            return $fraudCheck;
        }

        return [
            'status' => 'ready',
            'message' => __('admin/modules.isbank_ready'),
            'data' => [
                'payment_method' => 'isbank',
                'amount' => $params['amount'],
                'currency' => $params['currency'] ?? 'TRY',
                'order_id' => $params['order_id'] ?? null,
            ],
        ];
    }

    /**
     * 2D odeme islemini gerceklestirir (3D Secure olmadan)
     * CC5Request Type=Auth (WHMCS finansbank.php:43 — IPAddress + Mode=P dahil EST 2D setine uygun)
     *
     * @return array
     */
    public function makePayment(array $params)
    {
        $cardNumber = preg_replace('/\s+/', '', $params['card_number']);
        $expMonth = str_pad($params['exp_month'], 2, '0', STR_PAD_LEFT);
        $expYear = substr($params['exp_year'], -2);
        $expires = $expMonth . '/' . $expYear;

        $currencyCode = $this->config['currency_code'] ?? '949';
        $orderId = $params['order_id'] ?? 'ORD-' . time();

        // Taksit (WiseCP capture:55-57 — <1 ise bos; EST Auth XML non-3D'de de <Taksit> kabul eder)
        $installment = (string) ($params['installment'] ?? '');
        if ((int) $installment < 1) {
            $installment = '';
        }

        $xmlData = $this->buildXmlRequest('Auth', [
            'Name' => $this->config['name'],
            'Password' => $this->config['password'],
            'ClientId' => $this->config['client_id'],
            'IPAddress' => $params['user_ip'] ?? ($_SERVER['REMOTE_ADDR'] ?? ''),
            'Email' => $params['customer_email'] ?? '',
            'Mode' => 'P',
            'OrderId' => $orderId,
            'Number' => $cardNumber,
            'Expires' => $expires,
            'Cvv2Val' => $params['cvv'],
            'Total' => number_format($params['amount'], 2, '.', ''),
            'Currency' => $currencyCode,
            'Taksit' => $installment,
        ]);

        $response = $this->postXml($this->apiUrl, $xmlData, ['Content-Type: text/xml; charset=ISO-8859-9']);
        $this->logCurlError($response);
        $parsed = $this->parseXmlResponse($response['raw_response'] ?? '');

        if ($parsed && ($parsed['Response'] ?? '') === 'Approved' && ($parsed['ProcReturnCode'] ?? '') === '00') {
            return [
                'status' => 'success',
                'message' => __('admin/modules.isbank_payment_success'),
                'transaction_id' => $parsed['TransId'] ?? '',
                'auth_code' => $parsed['AuthCode'] ?? '',
                'order_id' => $orderId,
                'data' => $parsed,
            ];
        }

        return [
            'status' => 'error',
            'message' => $parsed['ErrMsg'] ?? __('admin/modules.isbank_payment_failed'),
            'error_code' => $parsed['ProcReturnCode'] ?? '',
            'data' => $parsed ?? $response,
        ];
    }

    /**
     * Banka callback verisini isler (3D yonlendirme donusu)
     *
     * @return array
     */
    public function handlePaymentCallback(array $params)
    {
        // Hash dogrulamasi (fail-closed) — imza gecersizse odeme ASLA basarili sayilmaz
        if (! $this->validate3DResponse($params)) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.isbank_callback_invalid'),
            ];
        }

        $mdStatus = $params['mdStatus'] ?? '0';

        // 3D dogrulama basariliysa provizyon tamamla
        if (in_array($mdStatus, ['1', '2', '3', '4'], true)) {
            return $this->complete3DPayment($params);
        }

        return [
            'status' => 'failed',
            'message' => $params['ErrMsg'] ?? __('admin/modules.isbank_payment_failed'),
            'md_status' => $mdStatus,
            'md_error' => $params['mdErrorMsg'] ?? '',
            'data' => $params,
        ];
    }

    /**
     * Odeme iadesi yapar - CC5Request Type=Credit (EST tam-iade)
     *
     * @return array
     */
    public function refundPayment(array $params)
    {
        $xmlData = $this->buildXmlRequest('Credit', [
            'Name' => $this->config['name'],
            'Password' => $this->config['password'],
            'ClientId' => $this->config['client_id'],
            'OrderId' => $params['order_id'] ?? '',
            'Total' => isset($params['amount']) ? number_format($params['amount'], 2, '.', '') : '',
            'Currency' => $this->config['currency_code'] ?? '949',
        ]);

        $response = $this->postXml($this->apiUrl, $xmlData, ['Content-Type: text/xml; charset=ISO-8859-9']);
        $this->logCurlError($response);
        $parsed = $this->parseXmlResponse($response['raw_response'] ?? '');

        if ($parsed && ($parsed['Response'] ?? '') === 'Approved' && ($parsed['ProcReturnCode'] ?? '') === '00') {
            return [
                'status' => 'success',
                'message' => __('admin/modules.isbank_refund_success'),
                'transaction_id' => $parsed['TransId'] ?? '',
                'auth_code' => $parsed['AuthCode'] ?? '',
                'data' => $parsed,
            ];
        }

        return [
            'status' => 'error',
            'message' => $parsed['ErrMsg'] ?? __('admin/modules.isbank_refund_failed'),
            'error_code' => $parsed['ProcReturnCode'] ?? '',
            'data' => $parsed ?? $response,
        ];
    }

    /**
     * Odeme linki olusturma - 3D form verisi dondurur
     * EST est3Dgate kart-verisiz hosted link URETMEZ (PAN client-side gerekir).
     *
     * @return array
     */
    public function generatePaymentLink(array $params)
    {
        // 3D form verisi uzerinden yonlendirme destegi
        if (! empty($params['card_number']) && ! empty($params['amount'])) {
            return $this->start3DPayment($params);
        }

        return [
            'status' => 'error',
            'message' => __('admin/modules.isbank_link_not_supported'),
        ];
    }

    public function start3DPayment(array $params)
    {
        $cardNumber = preg_replace('/\s+/', '', $params['card_number']);
        $expMonth = str_pad($params['exp_month'], 2, '0', STR_PAD_LEFT);
        $expYear = substr($params['exp_year'], -2);

        $currencyCode = $this->config['currency_code'] ?? '949';
        $storeType = $this->config['store_type'] ?? '3d';
        $orderId = $params['order_id'] ?? 'ORD-' . time();
        $amount = number_format($params['amount'], 2, '.', '');
        $okUrl = $params['success_url'];
        $failUrl = $params['fail_url'];
        $rnd = microtime();
        $clientId = $this->config['client_id'];
        $storeKey = $this->config['store_key'];
        $islemtipi = 'Auth';

        // Taksit (WiseCP capture:55-57 — <1 ise bos gonderilir)
        $installment = (string) ($params['installment'] ?? '');
        if ((int) $installment < 1) {
            $installment = '';
        }

        // Istek hash (NestPay/EST est3Dgate — yetkili 3D sozlesmesi):
        //   MODEL 1 '3d'               : clientid+oid+amount+okUrl+failUrl+islemtipi+rnd+storekey (TAKSIT YOK)
        //   MODEL 2/3 '3d_pay(_hosting)': clientid+oid+amount+okUrl+failUrl+islemtipi+taksit+rnd+storekey
        // callbackUrl hash'e GIRMEZ (est3Dgate ayri callbackurl POST etmez; yanit okUrl/failUrl'e doner).
        // SHA-1 -> base64(pack('H*', sha1(hashstr))).
        if ($storeType === '3d') {
            $hashStr = $clientId . $orderId . $amount . $okUrl . $failUrl . $islemtipi . $rnd . $storeKey;
        } else {
            $hashStr = $clientId . $orderId . $amount . $okUrl . $failUrl . $islemtipi . $installment . $rnd . $storeKey;
        }
        $hash = base64_encode(pack('H*', sha1($hashStr)));

        $formData = [
            'clientid' => $clientId,
            'storetype' => $storeType,
            'amount' => $amount,
            'currency' => $currencyCode,
            'oid' => $orderId,
            'okUrl' => $okUrl,
            'failUrl' => $failUrl,
            'islemtipi' => $islemtipi,
            'taksit' => $installment,
            'rnd' => $rnd,
            'hash' => $hash,
            'pan' => $cardNumber,
            'Ecom_Payment_Card_ExpDate_Month' => $expMonth,
            'Ecom_Payment_Card_ExpDate_Year' => $expYear,
            'cv2' => $params['cvv'],
            'cardType' => $this->detectCardType($cardNumber),
            'lang' => ($params['lang'] ?? 'tr') === 'tr' ? 'tr' : 'en',
            'email' => $params['customer_email'] ?? '',
        ];

        return [
            'status' => '3d_redirect',
            'message' => __('admin/modules.isbank_3d_redirect'),
            'gateway_url' => $this->gatewayUrl,
            'form_data' => $formData,
            'method' => 'POST',
            'order_id' => $orderId,
        ];
    }

    public function complete3DPayment(array $params)
    {
        // Hash dogrulamasi (fail-closed)
        if (! $this->validate3DResponse($params)) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.isbank_3d_hash_invalid'),
            ];
        }

        // mdStatus kontrol (1=tam dogrulama, 2,3,4=kismi dogrulama)
        $mdStatus = $params['mdStatus'] ?? '0';
        $validStatuses = ['1', '2', '3', '4'];

        if (! in_array($mdStatus, $validStatuses, true)) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.isbank_3d_auth_failed'),
                'md_status' => $mdStatus,
                'md_error' => $params['mdErrorMsg'] ?? '',
                'data' => $params,
            ];
        }

        $storeType = $this->config['store_type'] ?? '3d';

        // MODEL 2 / MODEL 3 (3d_pay, 3d_pay_hosting): est3Dgate 3D dogrulama + ODEMEYI
        // birlikte yapar. Ikinci bir CC5 /fim/api Auth cagrisi MUKERRER CEKIM olur.
        // Bu nedenle gate donusunu (okUrl POST'undaki Response/ProcReturnCode) DOGRUDAN
        // kabul ederiz (NestPay/EST 3D sozlesmesi MODEL 2/3).
        if ($storeType !== '3d') {
            if (($params['Response'] ?? '') === 'Approved' && ($params['ProcReturnCode'] ?? '') === '00') {
                return [
                    'status' => 'success',
                    'message' => __('admin/modules.isbank_payment_success'),
                    'transaction_id' => $params['TransId'] ?? '',
                    'auth_code' => $params['AuthCode'] ?? '',
                    'order_id' => $params['oid'] ?? '',
                    'md_status' => $mdStatus,
                    'data' => $params,
                ];
            }

            return [
                'status' => 'error',
                'message' => $params['ErrMsg'] ?? __('admin/modules.isbank_provision_failed'),
                'error_code' => $params['ProcReturnCode'] ?? '',
                'md_status' => $mdStatus,
                'data' => $params,
            ];
        }

        // MODEL 1 (3d): est3Dgate YALNIZ 3D dogrulama yapar. Odeme icin merchant
        // simdi CC5 /fim/api Auth cagrisini yapmalidir (Kriweb qnb::handleCapture).
        // 3D dogrulama sonuclari gonderilir; PAN/CVV/Expires GONDERILMEZ, Number=md.
        $currencyCode = $this->config['currency_code'] ?? '949';

        // Taksit (banka POST'undan; <1 ise bos)
        $installment = (string) ($params['taksit'] ?? '');
        if ((int) $installment < 1) {
            $installment = '';
        }

        $xmlData = $this->buildXmlRequest('Auth', [
            'Name' => $this->config['name'],
            'Password' => $this->config['password'],
            'ClientId' => $this->config['client_id'],
            'IPAddress' => $params['user_ip'] ?? ($_SERVER['REMOTE_ADDR'] ?? ''),
            'Email' => $params['email'] ?? ($params['customer_email'] ?? ''),
            'Mode' => 'P',
            'OrderId' => $params['oid'] ?? '',
            'Number' => $params['md'] ?? '',
            'Total' => number_format((float) ($params['amount'] ?? 0), 2, '.', ''),
            'Currency' => $currencyCode,
            'Taksit' => $installment,
            'PayerTxnId' => $params['xid'] ?? '',
            'PayerSecurityLevel' => $params['eci'] ?? '',
            'PayerAuthenticationCode' => $params['cavv'] ?? '',
            'CardholderPresentCode' => '13',
        ]);

        $response = $this->postXml($this->apiUrl, $xmlData, ['Content-Type: text/xml; charset=ISO-8859-9']);
        $this->logCurlError($response);
        $parsed = $this->parseXmlResponse($response['raw_response'] ?? '');

        if ($parsed && ($parsed['Response'] ?? '') === 'Approved' && ($parsed['ProcReturnCode'] ?? '') === '00') {
            return [
                'status' => 'success',
                'message' => __('admin/modules.isbank_payment_success'),
                'transaction_id' => $parsed['TransId'] ?? '',
                'auth_code' => $parsed['AuthCode'] ?? '',
                'order_id' => $params['oid'] ?? '',
                'md_status' => $mdStatus,
                'data' => $parsed,
            ];
        }

        return [
            'status' => 'error',
            'message' => $parsed['ErrMsg'] ?? __('admin/modules.isbank_provision_failed'),
            'error_code' => $parsed['ProcReturnCode'] ?? '',
            'md_status' => $mdStatus,
            'data' => $parsed ?? $response,
        ];
    }

    /**
     * Baglanti testi yapar
     *
     * @return array
     */
    public function testConnection(array $params = [])
    {
        $xmlData = $this->buildXmlRequest('Auth', [
            'Name' => $this->config['name'],
            'Password' => $this->config['password'],
            'ClientId' => $this->config['client_id'],
            'Mode' => 'P',
            'OrderId' => 'TEST-' . time(),
            'Number' => '4355084355084358',
            'Expires' => '12/30',
            'Cvv2Val' => '000',
            'Total' => '1.00',
            'Currency' => $this->config['currency_code'] ?? '949',
        ]);

        $response = $this->postXml($this->apiUrl, $xmlData, ['Content-Type: text/xml; charset=ISO-8859-9']);
        $this->logCurlError($response);
        $parsed = $this->parseXmlResponse($response['raw_response'] ?? '');

        // Baglanti basarili ise (hata veya onay farketmez, API cevap verdiyse baglanti var)
        if ($parsed && isset($parsed['Response'])) {
            return [
                'status' => 'success',
                'message' => __('admin/modules.isbank_connection_success'),
                'data' => [
                    'response' => $parsed['Response'],
                    'proc_return_code' => $parsed['ProcReturnCode'] ?? '',
                ],
            ];
        }

        return [
            'status' => 'error',
            'message' => __('admin/modules.isbank_connection_failed'),
            'data' => $response,
        ];
    }

    /**
     * Taksit planlari (WiseCP installment_rates:22-40 portu — 'N : oran' satir-parse)
     * Config 'installment' acik degilse bos doner (tek-cekim abstract default'la calisir).
     */
    public function getInstallmentPlans(float $amount, ?string $currencyCode = null): array
    {
        $enabled = filter_var($this->config['installment'] ?? false, FILTER_VALIDATE_BOOLEAN);
        if (! $enabled) {
            return [];
        }

        $maxInstallment = (int) ($this->config['max_installment'] ?? 12);
        $rates = (string) ($this->config['installment_commission'] ?? '');

        // Tek-cekim daima ilk plan.
        $plans = [[
            'count' => 1, 'rate' => 0.0, 'fee' => 0.0, 'surcharge' => 0.0,
            'total' => round($amount, 2), 'monthly' => round($amount, 2),
            'surcharge_applied_by' => $this->installmentSurchargeMode,
            'label' => '1',
        ]];

        if ($rates === '') {
            return $plans;
        }

        foreach (explode("\n", $rates) as $line) {
            $column = explode(':', $line);
            $count = (int) trim($column[0] ?? '');
            if ($count < 2 || ($maxInstallment > 0 && $count > $maxInstallment)) {
                continue;
            }

            $rate = (float) trim($column[1] ?? '0');
            $surcharge = $this->installmentSurchargeMode === 'procp'
                ? round($amount * ($rate / 100), 2)
                : 0.0;
            $total = round($amount + $surcharge, 2);

            $plans[] = [
                'count' => $count,
                'rate' => $rate,
                'fee' => 0.0,
                'surcharge' => $surcharge,
                'total' => $total,
                'monthly' => round($total / $count, 2),
                'surcharge_applied_by' => $this->installmentSurchargeMode,
                'label' => (string) $count,
            ];
        }

        return $plans;
    }

    /**
     * Konfigurasyon dogrulama
     *
     * @return array
     */
    public function validateConfig()
    {
        $required = ['client_id', 'name', 'password', 'store_key'];
        $missing = [];

        foreach ($required as $field) {
            if (empty($this->config[$field])) {
                $missing[] = $field;
            }
        }

        if (! empty($missing)) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.isbank_config_missing', ['fields' => implode(', ', $missing)]),
            ];
        }

        return [
            'status' => 'success',
            'message' => __('admin/modules.isbank_config_valid'),
        ];
    }

    /**
     * Modulun destekledigi ozellikleri dondurur
     */
    public function getFeatures(): array
    {
        return [
            'refund' => true,
            '3d_secure' => true,
            'save_card' => false,
            'recurring' => false,
            'fraud_check' => true,
            'installment' => true,
        ];
    }

    /**
     * Admin paneli icin konfigurasyon alanlari
     */
    public function getConfigFields(): array
    {
        return array_merge(parent::getConfigFields(), [
            'client_id' => [
                'type' => 'text',
                'label' => __('admin/modules.isbank_field_client_id'),
                'description' => __('admin/modules.isbank_field_client_id_desc'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter Client ID',
            ],
            'name' => [
                'type' => 'text',
                'label' => __('admin/modules.isbank_field_name'),
                'description' => __('admin/modules.isbank_field_name_desc'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter API username',
            ],
            'password' => [
                'type' => 'password',
                'label' => __('admin/modules.isbank_field_password'),
                'description' => __('admin/modules.isbank_field_password_desc'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter API password',
            ],
            'store_key' => [
                'type' => 'password',
                'label' => __('admin/modules.isbank_field_store_key'),
                'description' => __('admin/modules.isbank_field_store_key_desc'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter store key',
            ],
            'store_type' => [
                'type' => 'select',
                'label' => __('admin/modules.isbank_field_store_type'),
                'description' => __('admin/modules.isbank_field_store_type_desc'),
                'required' => true,
                'value' => '3d',
                'options' => [
                    '3d' => '3D Secure',
                    '3d_pay' => '3D Pay',
                    '3d_pay_hosting' => '3D Pay Hosting',
                ],
            ],
            'currency_code' => [
                'type' => 'select',
                'label' => __('admin/modules.isbank_field_currency_code'),
                'description' => __('admin/modules.isbank_field_currency_code_desc'),
                'required' => true,
                'value' => '949',
                'options' => [
                    '949' => 'TRY - Turkish Lira',
                    '840' => 'USD - US Dollar',
                    '978' => 'EUR - Euro',
                ],
            ],
            'installment' => [
                'type' => 'checkbox',
                'label' => __('admin/modules.isbank_field_installment'),
                'description' => __('admin/modules.isbank_field_installment_desc'),
                'value' => 'false',
            ],
            'installment_commission' => [
                'type' => 'textarea',
                'label' => __('admin/modules.isbank_field_installment_commission'),
                'description' => __('admin/modules.isbank_field_installment_commission_desc'),
                'value' => '',
            ],
            'max_installment' => [
                'type' => 'text',
                'label' => __('admin/modules.isbank_field_max_installment'),
                'description' => __('admin/modules.isbank_field_max_installment_desc'),
                'value' => '12',
            ],
        ]);
    }

    /**
     * Fraud kontrolu yapar
     *
     * @return array
     */
    public function performPreFraudCheck(array $params)
    {
        $riskScore = 'low';
        $reasons = [];

        // IP kontrolleri
        if (isset($params['user_ip'])) {
            $ip = $params['user_ip'];
            if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
                $riskScore = 'medium';
                $reasons[] = __('admin/modules.isbank_fraud_private_ip');
            }
        }

        // Tutar kontrolleri
        if (isset($params['amount']) && $params['amount'] > 10000) {
            $riskScore = 'high';
            $reasons[] = __('admin/modules.isbank_fraud_high_amount');
        }

        // Kart numarasi kontrol
        if (isset($params['card_number'])) {
            $cardNumber = preg_replace('/\s+/', '', $params['card_number']);
            if (! $this->luhnCheck($cardNumber)) {
                $riskScore = 'high';
                $reasons[] = __('admin/modules.isbank_fraud_invalid_card');
            }
        }

        return [
            'status' => $riskScore === 'high' ? 'error' : 'success',
            'risk_score' => $riskScore,
            'message' => $riskScore === 'high'
                ? __('admin/modules.isbank_fraud_blocked')
                : __('admin/modules.isbank_fraud_passed'),
            'reasons' => $reasons,
        ];
    }

    // =========================================================================
    // URL Helpers
    // =========================================================================

    /**
     * API URL dondurur - test veya canli
     */
    public function getApiUrl(): string
    {
        return $this->isTestMode()
            ? 'https://entegrasyon.asseco-see.com.tr/fim/api'
            : 'https://sanalpos.isbank.com.tr/fim/api';
    }

    /**
     * 3D Gateway URL dondurur - test veya canli
     */
    public function get3DGatewayUrl(): string
    {
        return $this->isTestMode()
            ? 'https://entegrasyon.asseco-see.com.tr/fim/est3Dgate'
            : 'https://sanalpos.isbank.com.tr/fim/est3Dgate';
    }

    // =========================================================================
    // Private Helper Methods
    // =========================================================================

    /**
     * CC5Request XML olusturur
     */
    private function buildXmlRequest(string $type, array $params): string
    {
        $xml = '<?xml version="1.0" encoding="ISO-8859-9"?>' . "\n";
        $xml .= '<CC5Request>' . "\n";
        $xml .= '  <Type>' . htmlspecialchars($type, ENT_XML1, 'ISO-8859-9') . '</Type>' . "\n";

        foreach ($params as $key => $value) {
            $xml .= '  <' . $key . '>' . htmlspecialchars((string) $value, ENT_XML1, 'ISO-8859-9') . '</' . $key . '>' . "\n";
        }

        $xml .= '</CC5Request>';

        return $xml;
    }

    /**
     * Banka XML cevabini parse eder
     */
    private function parseXmlResponse(?string $rawResponse): ?array
    {
        if (empty($rawResponse)) {
            return null;
        }

        try {
            libxml_use_internal_errors(true);
            $xml = simplexml_load_string($rawResponse);
            libxml_clear_errors();

            if ($xml === false) {
                return null;
            }

            $result = [];
            foreach ($xml->children() as $child) {
                $result[$child->getName()] = (string) $child;
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('Isbank XML parse error', [
                'error' => $e->getMessage(),
            ]);

            return null;
        }
    }

    /**
     * 3D Secure donus cevabini dogrular (fail-closed)
     * WiseCP Isbank callback:80-92 (EST v1): HASHPARAMS'a gore paramsval kur,
     * HASHPARAMSVAL capraz-kontrol + HASH = base64(pack H* sha1(paramsval+storeKey)).
     */
    private function validate3DResponse(array $params): bool
    {
        $hashParams = $params['HASHPARAMS'] ?? '';
        $hashParamsVal = $params['HASHPARAMSVAL'] ?? '';
        $hash = $params['HASH'] ?? '';

        if (empty($hashParams) || empty($hash)) {
            return false;
        }

        // HASHPARAMS ':' ile ayrilmis alan adlarindan paramsval kur (WiseCP callback:80-89)
        $paramsVal = '';
        foreach (explode(':', $hashParams) as $paramName) {
            if ($paramName !== '') {
                $paramsVal .= $params[$paramName] ?? '';
            }
        }

        // Capraz-kontrol: bankanin bildirdigi HASHPARAMSVAL, bizim kurdugumuzla eslesmeli
        if (! empty($hashParamsVal) && ! $this->secureCompare($paramsVal, $hashParamsVal)) {
            return false;
        }

        // Hash = base64(pack("H*", sha1(paramsval + storeKey))) — EST v1 SHA-1
        $calculatedHash = base64_encode(pack('H*', sha1($paramsVal . ($this->config['store_key'] ?? ''))));

        return $this->secureCompare($calculatedHash, $hash);
    }

    /**
     * curl hatasini loglar (PAN/CVV/raw_response HARIC — yalniz transport hatasi)
     */
    private function logCurlError(array $response): void
    {
        if (! empty($response['error'])) {
            Log::error('Isbank API transport error', [
                'endpoint' => $this->apiUrl,
                'error' => $response['error'],
                'http_code' => $response['http_code'] ?? null,
            ]);
        }
    }

    /**
     * Kart tipini tespit eder
     */
    private function detectCardType(string $cardNumber): string
    {
        $cardNumber = preg_replace('/\s+/', '', $cardNumber);

        if (preg_match('/^4/', $cardNumber)) {
            return '1'; // Visa
        }

        if (preg_match('/^5[1-5]/', $cardNumber)) {
            return '2'; // MasterCard
        }

        if (preg_match('/^3[47]/', $cardNumber)) {
            return '3'; // Amex
        }

        return '1'; // Varsayilan Visa
    }

    /**
     * Luhn algoritmasi ile kart numarasi dogrulama
     */
    private function luhnCheck(string $number): bool
    {
        $number = preg_replace('/\D/', '', $number);
        $length = strlen($number);

        if ($length < 13 || $length > 19) {
            return false;
        }

        $sum = 0;
        $alternate = false;

        for ($i = $length - 1; $i >= 0; $i--) {
            $digit = (int) $number[$i];

            if ($alternate) {
                $digit *= 2;
                if ($digit > 9) {
                    $digit -= 9;
                }
            }

            $sum += $digit;
            $alternate = ! $alternate;
        }

        return $sum % 10 === 0;
    }

    public function getSupportedFeatures(): array
    {
        return $this->getFeatures();
    }
}
