<?php

namespace App\Modules\Payment\Ziraat;

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

class Ziraat extends AbstractPayment
{
    protected $apiUrl;

    protected $gatewayUrl;

    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)
    {
        // EST/NestPay kart-token (saved-card) desteklemez; save_card=false +
        // payWithSavedCard unsupported. Token dali kaldirildi (olu/yaniltici yol).
        $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.ziraat_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.ziraat_invalid_card'),
            ];
        }

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

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

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

    /**
     * 2D odeme islemini gerceklestirir (3D Secure olmadan)
     * CC5Request formati ile XML istegi gonderir
     *
     * @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: >1 ise sayi, aksi halde bos (EST tek-cekim). Ref: Finansbank.php:89/104.
        $taksit = ((int) ($params['installment'] ?? 0) > 1) ? (string) (int) $params['installment'] : '';

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

        $response = $this->postEstXml($xmlData);
        $parsed = $this->parseXmlResponse($response['raw_response'] ?? '');

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

        return [
            'status' => 'error',
            'message' => $parsed['ErrMsg'] ?? __('admin/modules.ziraat_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
        if (! $this->validate3DResponse($params)) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.ziraat_callback_invalid'),
            ];
        }

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

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

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

    /**
     * Odeme iadesi yapar
     *
     * @return array
     */
    public function refundPayment(array $params)
    {
        $fields = [
            'Name' => $this->config['name'],
            'Password' => $this->config['password'],
            'ClientId' => $this->config['client_id'],
            'OrderId' => $params['order_id'] ?? '',
            'Currency' => $this->config['currency_code'] ?? '949',
        ];

        // EST Credit: kismi iade Total ile; tam iade Total alanini HIC gondermez.
        if (isset($params['amount']) && $params['amount'] !== '' && (float) $params['amount'] > 0) {
            $fields['Total'] = number_format($params['amount'], 2, '.', '');
        }

        $xmlData = $this->buildXmlRequest('Credit', $fields);

        $response = $this->postEstXml($xmlData);
        $parsed = $this->parseXmlResponse($response['raw_response'] ?? '');

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

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

    /**
     * Odeme linki olusturma - 3D form verisi dondurur
     *
     * @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.ziraat_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_pay';
        $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: MODEL 1 '3d' est3Dgate SADECE 3D dogrular, taksit yoktur -> tek-cekim (bos).
        // MODEL 2/3 gate odemeyi yaptigindan taksit gecerlidir.
        $is3dOnly = ($storeType === '3d');
        $taksit = (! $is3dOnly && isset($params['installment']) && (int) $params['installment'] > 1)
            ? (string) (int) $params['installment']
            : '';

        // Resmi EST/NestPay est3Dgate hash sozlesmesi storetype'a gore FARKLI:
        //   MODEL 1 '3d'             : clientid+oid+amount+okUrl+failUrl+rnd+storeKey (islemtipi/taksit YOK)
        //   MODEL 2 '3d_pay' / MODEL 3 '3d_pay_hosting':
        //                             clientid+oid+amount+okUrl+failUrl+islemtipi+taksit+rnd+storeKey
        $hashFields = [
            'clientid' => $clientId,
            'oid' => $orderId,
            'amount' => $amount,
            'okUrl' => $okUrl,
            'failUrl' => $failUrl,
        ];
        if (! $is3dOnly) {
            $hashFields['islemtipi'] = $islemtipi;
            $hashFields['taksit'] = $taksit;
        }
        $hashFields['rnd'] = $rnd;

        $hash = $this->generateHash($hashFields, $storeKey);

        $formData = [
            'clientid' => $clientId,
            'storetype' => $storeType,
            'amount' => $amount,
            'currency' => $currencyCode,
            'oid' => $orderId,
            'okUrl' => $okUrl,
            'failUrl' => $failUrl,
            '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',
            'islemtipi' => $islemtipi,
            'taksit' => $taksit,
            'email' => $params['customer_email'] ?? '',
        ];

        return [
            'status' => '3d_redirect',
            'message' => __('admin/modules.ziraat_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.ziraat_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)) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.ziraat_3d_auth_failed'),
                'md_status' => $mdStatus,
                'md_error' => $params['mdErrorMsg'] ?? '',
                'data' => $params,
            ];
        }

        // ODEME-KRITIK storetype dallanmasi (EST/NestPay 3-D Secure sozlesmesi):
        //   MODEL 1 '3d'             = est3Dgate YALNIZ 3D dogrulama yapar; odeme YAPILMADI.
        //                              => merchant SONRA CC5 /fim/api Auth cagrisi YAPMALI.
        //   MODEL 2 '3d_pay'         = gate 3D + odemeyi BIRLIKTE yapar.
        //   MODEL 3 '3d_pay_hosting' = gate kart sayfasini kendi host eder + 3D + odeme.
        //                              => (2/3) CC5 cagrisi YOK; gate donusu (okUrl POST) dogrudan
        //                                 kabul edilir. CC5 Auth cagirmak = IKINCI cekim (cift-cekim).
        // Config-gated: karar tamamen admin'in sectigi store_type config'ine bagli.
        $storeType = $this->config['store_type'] ?? '3d_pay';

        if ($storeType === '3d') {
            // MODEL 1: gate sadece 3D dogruladi; provizyonu biz aliriz.
            return $this->acquireProvision3D($params, $mdStatus);
        }

        // MODEL 2 / MODEL 3: gate odemeyi zaten tamamladi. Gate donusundeki odeme
        // sonucunu (okUrl POST alanlari: Response/ProcReturnCode/AuthCode/TransId)
        // dogrudan degerlendir; CC5 cagrisi YAPILMAZ.
        $response = $params['Response'] ?? '';
        $procReturnCode = $params['ProcReturnCode'] ?? '';

        if ($response === 'Approved' && $procReturnCode === '00') {
            return [
                'status' => 'success',
                'message' => __('admin/modules.ziraat_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.ziraat_provision_failed'),
            'error_code' => $procReturnCode,
            'md_status' => $mdStatus,
            'data' => $params,
        ];
    }

    /**
     * MODEL 1 ('3d') provizyon: 3D dogrulama sonrasi CC5 /fim/api Auth cagrisi.
     * NestPay 3D-alanlari: Number=md, PayerSecurityLevel=eci,
     * PayerAuthenticationCode=cavv, PayerTxnId=xid. PAN/CVV/expiry GONDERILMEZ.
     * Total 3D sorgusundaki tutarla ayni gonderilir (bkz. NestPay 'ONEMLI BILGI').
     *
     * @return array
     */
    private function acquireProvision3D(array $params, string $mdStatus): array
    {
        $currencyCode = $this->config['currency_code'] ?? '949';
        // Taksit: banka 3D POST'undan (est3Dgate 'taksit' formu). <1 ise bos (tek-cekim).
        $taksit = (string) ($params['taksit'] ?? '');
        if ((int) $taksit < 1) {
            $taksit = '';
        }

        $xmlData = $this->buildXmlRequest('Auth', [
            'Name' => $this->config['name'],
            'Password' => $this->config['password'],
            'ClientId' => $this->config['client_id'],
            'OrderId' => $params['oid'] ?? '',
            'Total' => number_format((float) ($params['amount'] ?? 0), 2, '.', ''),
            'Currency' => $currencyCode,
            'Number' => $params['md'] ?? '',
            // EST 3D-auth alanlari: PayerSecurityLevel=eci, PayerAuthenticationCode=cavv, PayerTxnId=xid
            'PayerSecurityLevel' => $params['eci'] ?? '',
            'PayerAuthenticationCode' => $params['cavv'] ?? '',
            'PayerTxnId' => $params['xid'] ?? '',
            'Taksit' => $taksit,
            'CardholderPresentCode' => '13',
        ]);

        $response = $this->postEstXml($xmlData);
        $parsed = $this->parseXmlResponse($response['raw_response'] ?? '');

        if ($parsed && ($parsed['Response'] ?? '') === 'Approved' && ($parsed['ProcReturnCode'] ?? '') === '00') {
            return [
                'status' => 'success',
                'message' => __('admin/modules.ziraat_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.ziraat_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'],
            'Total' => '1.00',
            'Currency' => $this->config['currency_code'] ?? '949',
            'Number' => '4355084355084358',
            'Expires' => '12/30',
            'Cvv2Val' => '000',
            'OrderId' => 'TEST-' . time(),
        ]);

        $response = $this->postEstXml($xmlData);
        $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.ziraat_connection_success'),
                'data' => [
                    'response' => $parsed['Response'],
                    'proc_return_code' => $parsed['ProcReturnCode'] ?? '',
                ],
            ];
        }

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

    /**
     * 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.ziraat_config_missing', ['fields' => implode(', ', $missing)]),
            ];
        }

        return [
            'status' => 'success',
            'message' => __('admin/modules.ziraat_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.ziraat_field_client_id'),
                'description' => __('admin/modules.ziraat_field_client_id_desc'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter Client ID',
            ],
            'name' => [
                'type' => 'text',
                'label' => __('admin/modules.ziraat_field_name'),
                'description' => __('admin/modules.ziraat_field_name_desc'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter API username',
            ],
            'password' => [
                'type' => 'password',
                'label' => __('admin/modules.ziraat_field_password'),
                'description' => __('admin/modules.ziraat_field_password_desc'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter API password',
            ],
            'store_key' => [
                'type' => 'password',
                'label' => __('admin/modules.ziraat_field_store_key'),
                'description' => __('admin/modules.ziraat_field_store_key_desc'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter store key',
            ],
            'store_type' => [
                'type' => 'select',
                'label' => __('admin/modules.ziraat_field_store_type'),
                'description' => __('admin/modules.ziraat_field_store_type_desc'),
                'required' => true,
                'value' => '3d_pay',
                'options' => [
                    '3d_pay' => '3D Pay',
                    '3d' => '3D Secure',
                    '3d_pay_hosting' => '3D Pay Hosting',
                ],
            ],
            'currency_code' => [
                'type' => 'select',
                'label' => __('admin/modules.ziraat_field_currency_code'),
                'description' => __('admin/modules.ziraat_field_currency_code_desc'),
                'required' => true,
                'value' => '949',
                'options' => [
                    '949' => 'TRY - Turkish Lira',
                    '840' => 'USD - US Dollar',
                    '978' => 'EUR - Euro',
                ],
            ],
        ], $this->installmentConfigFields());
    }

    /**
     * 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.ziraat_fraud_private_ip');
            }
        }

        // Tutar kontrolleri
        if (isset($params['amount']) && $params['amount'] > 10000) {
            $riskScore = 'high';
            $reasons[] = __('admin/modules.ziraat_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.ziraat_fraud_invalid_card');
            }
        }

        return [
            'status' => $riskScore === 'high' ? 'error' : 'success',
            'risk_score' => $riskScore,
            'message' => $riskScore === 'high'
                ? __('admin/modules.ziraat_fraud_blocked')
                : __('admin/modules.ziraat_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://sanalpos2.ziraatbank.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://sanalpos2.ziraatbank.com.tr/fim/est3Dgate';
    }

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

    private function generateHash(array $params, string $storeKey): string
    {
        // Alanlar caller'in verdigi SIRAYLA birlestirilir (storetype'a gore islemtipi/taksit
        // dahil olabilir veya olmayabilir). EST/NestPay est3Dgate: SHA-1 + base64.
        $hashStr = '';
        foreach ($params as $value) {
            $hashStr .= (string) $value;
        }
        $hashStr .= $storeKey;

        return base64_encode(pack('H*', sha1($hashStr)));
    }

    /**
     * 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) {
            // PCI: ham banka cevabi (maskesiz PAN/AuthCode icerebilir) LOGLANMAZ — yalniz hata mesaji.
            Log::error('Ziraat XML parse error', [
                'error' => $e->getMessage(),
            ]);

            return null;
        }
    }

    private function validate3DResponse(array $params): bool
    {
        $hashParams = $params['HASHPARAMS'] ?? '';
        $hashParamsVal = $params['HASHPARAMSVAL'] ?? '';
        $hash = $params['HASH'] ?? '';

        // HASH her durumda zorunludur (fail-closed).
        if (empty($hash)) {
            return false;
        }

        // Alan sirasini belirle: banka HASHPARAMS gonderdiyse ONU kullan (en saglami);
        // yoksa islem tipine gore dokümante edilmis sabit sirayi kur.
        if (! empty($hashParams)) {
            $order = array_values(array_filter(explode(':', $hashParams), fn ($p) => $p !== ''));
        } else {
            $is3d = in_array(($params['mdStatus'] ?? ''), ['1', '2', '3', '4'], true)
                || isset($params['md']);
            $order = $is3d
                ? ['clientid', 'oid', 'AuthCode', 'ProcReturnCode', 'Response', 'mdStatus', 'cavv', 'eci', 'md', 'rnd']
                : ['clientid', 'oid', 'AuthCode', 'ProcReturnCode', 'Response', 'rnd'];
        }

        // Alan degerlerini SIRAYLA birlestir (HASHPARAMSVAL karsiligi).
        $paramsVal = '';
        foreach ($order as $paramName) {
            $paramsVal .= $params[$paramName] ?? '';
        }

        // Banka HASHPARAMSVAL bildirdiyse capraz-kontrol (WiseCP callback:86).
        if (! empty($hashParamsVal) && ! $this->secureCompare($paramsVal, $hashParamsVal)) {
            return false;
        }

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

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

    /**
     * EST/NestPay CC5Request XML gonderir (PRC-888 postXml transport, TLS acik).
     * EST fim/api ISO-8859-9 text/xml bekler; Content-Type elle veriliyor.
     */
    private function postEstXml(string $xmlData): array
    {
        return $this->postXml(
            $this->apiUrl,
            $xmlData,
            ['Content-Type: text/xml; charset=ISO-8859-9'],
            ['verify' => true, 'timeout' => 60, 'connect_timeout' => 30]
        );
    }

    /**
     * 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();
    }
}
