<?php

namespace App\Modules\Payment\Paysera;

use App\Core\Payment\AbstractPayment;

class Paysera extends AbstractPayment
{
    // WebToPay PAY_URL (WebToPay.php:43) — kanonik checkout host (www.paysera.com eski/marketing).
    protected $apiUrl = 'https://bank.paysera.com/pay/';

    // Paysera RSA public keys (www.paysera.com/download/public.key) — ss2 RSA-SHA1 doğrulaması için.
    // Sandbox test=1 akışında sandbox.paysera.com/download/public.key kullanılır.
    protected $publicKeyProd = "-----BEGIN CERTIFICATE-----\n"
        ."MIICPjCCAacCFCMd/AKCGrBmBZhasIEkapgL3ah5MA0GCSqGSIb3DQEBCwUAMF4x\n"
        ."CzAJBgNVBAYTAkxUMRMwEQYDVQQIDApTb21lLVN0YXRlMRAwDgYDVQQHDAdWaWxu\n"
        ."aXVzMRMwEQYDVQQKDApQYXlzZXJhIExUMRMwEQYDVQQLDApQYXlzZXJhIExUMB4X\n"
        ."DTI1MDIwNTE0MDcyNloXDTI3MDIwNTE0MDcyNlowXjELMAkGA1UEBhMCTFQxEzAR\n"
        ."BgNVBAgMClNvbWUtU3RhdGUxEDAOBgNVBAcMB1ZpbG5pdXMxEzARBgNVBAoMClBh\n"
        ."eXNlcmEgTFQxEzARBgNVBAsMClBheXNlcmEgTFQwgZ8wDQYJKoZIhvcNAQEBBQAD\n"
        ."gY0AMIGJAoGBAN5PbdX+Q21/+Gs1p79mwt9Fl3wT6izodn0JuC8H5frn2QEMGrm+\n"
        ."MwMJWRjqyJyfV9wV+6i0RxuEpIoOsMBD4OYIyb3oLsDiCoILk6qYg1q7FgN1uJ7t\n"
        ."X0YladtFcOz/ky7vbZ/lO45QbceE3+9ODy4LEisYhi/2J2G9NsPKJ5ULAgMBAAEw\n"
        ."DQYJKoZIhvcNAQELBQADgYEALNB62C0eTuPAgrSgv/mZYKMZvQ+T97qUDZ2l/PG+\n"
        ."Oby2Ij1Uhut8w7BFnv7tcDQ+QLksvpcoJ6+Hge0iROVDLioLhUMDC/mz1TtC9kmP\n"
        ."d+n4PzdcllupdknJi5BbEucZcHpvHd2xJieWX+KzcZ1TorteF7xd2/Keo86ClZb0\n"
        ."M5s=\n"
        ."-----END CERTIFICATE-----\n";

    protected $publicKeySandbox = "-----BEGIN PUBLIC KEY-----\n"
        ."MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsAvS0hO/ulGPsGKZj3dq\n"
        ."UaKLgoMm2dF6GdIaze/bfNzn+q4vqkufUVrpt0vlS6y2b64xNt+r5euB9ILWrHN0\n"
        ."aWmepIn8Jx5AgQ4n6/nqRWPp16cifuaJtImYpBWXIZlMozAObqvCU2Qxv8QJYl7R\n"
        ."k2pIYmYX4lbWMjKK9ffcgMgIdsFsLJ/XU81WjUy7rpEjAi4dhsB+OoNDSEnZIm9R\n"
        ."1esy8thXVcguYTkwuNVTQJOur53AIKkgkQOzH2yS9JN3HEo9lyhDPgDrM/I0GhOI\n"
        ."UR1Fi0C8FIHfeNFpmq2YTlXafH5efEqPSMSmxbgAQhcojWOQ6t3isRyVnFSVOpKi\n"
        ."wQIDAQAB\n"
        ."-----END PUBLIC KEY-----\n";

    /**
     * Paysera status code mapping:
     * 0 -> payment has not been executed
     * 1 -> payment successful (confirmed)
     * 2 -> payment accepted but not yet confirmed
     * 3 -> additional information needed
     */
    protected $statusMap = [
        0 => 'pending',
        1 => 'success',
        2 => 'pending',
        3 => 'pending',
    ];

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

    /**
     * Validate payment parameters and return ready status
     */
    public function attemptPayment(array $params)
    {
        $requiredParams = ['amount', 'currency', 'orderid'];

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

        if ($params['amount'] <= 0) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.paysera_invalid_amount'),
            ];
        }

        return [
            'status' => 'ready',
            'message' => __('admin/modules.paysera_ready'),
            'data' => [
                'payment_method' => 'paysera',
                'amount' => $params['amount'],
                'currency' => $params['currency'],
                'orderid' => $params['orderid'],
            ],
        ];
    }

    /**
     * Build payment data and redirect to Paysera
     */
    public function makePayment(array $params)
    {
        $projectId = $this->getConfig('project_id');
        $signPassword = $this->getConfig('sign_password');

        if (empty($projectId) || empty($signPassword)) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.paysera_config_incomplete'),
            ];
        }

        // Amount must be in minor units (1 EUR = 100 cents). number_format ile
        // float-round tuzağından kaçın (referans WiseCP Paysera.php:46).
        $amountInCents = (int) number_format((float) $params['amount'], 2, '', '');
        $currency = strtoupper($params['currency'] ?? 'EUR');
        $orderId = $params['orderid'] ?? $params['order_id'] ?? uniqid('paysera_');

        $paymentData = [
            'projectid' => $projectId,
            'orderid' => $orderId,
            'accepturl' => $params['success_url'] ?? $params['accepturl'] ?? '',
            'cancelurl' => $params['cancel_url'] ?? $params['cancelurl'] ?? '',
            'callbackurl' => $params['webhook_url'] ?? $params['callbackurl'] ?? '',
            'amount' => $amountInCents,
            'currency' => $currency,
            'test' => $this->isTestMode() ? 1 : 0,
            'version' => '1.6',
        ];

        // Add optional fields
        if (isset($params['country'])) {
            $paymentData['country'] = strtoupper($params['country']);
        }

        if (isset($params['paytext'])) {
            $paymentData['paytext'] = $params['paytext'];
        } else {
            $paymentData['paytext'] = __('admin/modules.paysera_payment_description', [
                'order_id' => $orderId,
            ]);
        }

        if (isset($params['customer_email'])) {
            $paymentData['p_email'] = $params['customer_email'];
        }

        if (isset($params['customer_name'])) {
            $nameParts = explode(' ', $params['customer_name'], 2);
            $paymentData['p_firstname'] = $nameParts[0] ?? '';
            $paymentData['p_lastname'] = $nameParts[1] ?? '';
        }

        // Encode data and generate signature
        $encodedData = $this->encodeData($paymentData);
        $sign = $this->generateSign($encodedData, $signPassword);

        $redirectUrl = $this->apiUrl . '?' . http_build_query([
            'data' => $encodedData,
            'sign' => $sign,
        ]);

        return [
            'status' => 'redirect',
            'message' => __('admin/modules.paysera_payment_created'),
            'transaction_id' => $orderId,
            'redirect_url' => $redirectUrl,
            'data' => [
                'orderid' => $orderId,
                'amount' => $params['amount'],
                'currency' => $currency,
                'encoded_data' => $encodedData,
                'sign' => $sign,
            ],
        ];
    }

    /**
     * Handle payment callback from Paysera
     * Decodes base64url data, verifies ss1 signature, checks payment status
     */
    public function handlePaymentCallback(array $params)
    {
        $signPassword = $this->getConfig('sign_password');

        $encodedData = $params['data'] ?? null;
        $ss1 = $params['ss1'] ?? null;
        $ss2 = $params['ss2'] ?? null;

        if (! $encodedData || (! $ss1 && ! $ss2)) {
            return [
                'status' => 'failed',
                'message' => __('admin/modules.paysera_callback_invalid'),
            ];
        }

        // Verify signature — fail-closed. Kanonik WebToPay getSigner (WebToPay.php:1945)
        // OpenSSL varsa DAİMA ss2=RSA-SHA1'i Paysera public.key ile tercih eder
        // (SS2SignChecker openssl_verify :2189-2197); ss1(md5) yalnız openssl YOKSA.
        if (! $this->verifyCallbackSignature($encodedData, $ss1, $ss2, $signPassword)) {
            return [
                'status' => 'failed',
                'message' => __('admin/modules.paysera_signature_invalid'),
            ];
        }

        // Decode the data (url-safe base64 — WebToPay decodeSafeUrlBase64 :2307).
        $decodedString = base64_decode(strtr($encodedData, ['-' => '+', '_' => '/']), true);

        if ($decodedString === false) {
            return [
                'status' => 'failed',
                'message' => __('admin/modules.paysera_data_decode_failed'),
            ];
        }

        parse_str($decodedString, $callbackData);

        $payseraStatus = (int) ($callbackData['status'] ?? -1);
        $orderId = $callbackData['orderid'] ?? null;
        $amount = isset($callbackData['amount']) ? (int) $callbackData['amount'] / 100 : 0;
        $currency = $callbackData['currency'] ?? '';

        // Verify project ID matches — strict compare (WebToPay.php:1265 (string)!==).
        $projectId = $this->getConfig('project_id');
        if (! isset($callbackData['projectid'])
            || (string) $callbackData['projectid'] !== (string) $projectId) {
            return [
                'status' => 'failed',
                'message' => __('admin/modules.paysera_project_mismatch'),
            ];
        }

        // Amount/currency manipülasyon koruması — beklenen sipariş tutarı/para birimi
        // callback'le eşleşmeli (referans checkPayment WiseCP Paysera.php:149-172).
        $expectedAmount = $params['expected_amount'] ?? $params['amount'] ?? null;
        $expectedCurrency = $params['expected_currency'] ?? $params['currency'] ?? null;
        $paidAmount = isset($callbackData['payamount'])
            ? (int) $callbackData['payamount'] / 100 : $amount;
        $paidCurrency = $callbackData['paycurrency'] ?? $currency;

        if ($expectedAmount !== null) {
            $expectedMinor = (int) number_format((float) $expectedAmount, 2, '', '');
            $amountMatch = ((int) ($callbackData['amount'] ?? -1) === $expectedMinor)
                || (isset($callbackData['payamount']) && (int) $callbackData['payamount'] === $expectedMinor);
            if (! $amountMatch) {
                return [
                    'status' => 'failed',
                    'message' => __('admin/modules.paysera_amount_mismatch'),
                ];
            }
        }
        if ($expectedCurrency !== null) {
            $currencyMatch = (strtoupper((string) $currency) === strtoupper((string) $expectedCurrency))
                || (strtoupper((string) $paidCurrency) === strtoupper((string) $expectedCurrency));
            if (! $currencyMatch) {
                return [
                    'status' => 'failed',
                    'message' => __('admin/modules.paysera_currency_mismatch'),
                ];
            }
        }

        // Map Paysera status to internal status
        $internalStatus = $this->statusMap[$payseraStatus] ?? 'failed';

        if ($internalStatus === 'success') {
            return [
                'status' => 'success',
                'message' => __('admin/modules.paysera_payment_success'),
                'transaction_id' => $orderId,
                'data' => [
                    'orderid' => $orderId,
                    'amount' => $amount,
                    'currency' => $currency,
                    'paysera_status' => $payseraStatus,
                    'requestid' => $callbackData['requestid'] ?? null,
                    'paytext' => $callbackData['paytext'] ?? null,
                ],
            ];
        }

        return [
            'status' => $internalStatus,
            'message' => __('admin/modules.paysera_payment_pending'),
            'transaction_id' => $orderId,
            'data' => [
                'orderid' => $orderId,
                'amount' => $amount,
                'currency' => $currency,
                'paysera_status' => $payseraStatus,
            ],
        ];
    }

    /**
     * Refund is not supported via Paysera redirect integration
     */
    public function refundPayment(array $params)
    {
        return [
            'status' => 'error',
            'message' => __('admin/modules.paysera_refund_not_supported'),
        ];
    }

    /**
     * Generate a payment link - delegates to makePayment
     */
    public function generatePaymentLink(array $params)
    {
        $result = $this->makePayment($params);

        if ($result['status'] === 'redirect') {
            return [
                'status' => 'success',
                'payment_url' => $result['redirect_url'],
                'transaction_id' => $result['transaction_id'],
                'data' => $result['data'],
            ];
        }

        return $result;
    }

    /**
     * Test connection by verifying configuration is complete
     */
    public function testConnection(array $params = [])
    {
        $validation = $this->validateConfig();

        if ($validation['status'] !== 'success') {
            return $validation;
        }

        // Paysera'nın canlı doğrulama endpoint'i yok (redirect checkout). En azından
        // encode + sign round-trip self-test'i yap: imza üretimi ve base64url çözümü
        // deterministik olmalı (ağ çağrısı YOK, global callApi'ye dokunulmaz).
        $signPassword = (string) $this->getConfig('sign_password');
        $probe = $this->encodeData(['projectid' => (string) $this->getConfig('project_id'), 'test' => 1]);
        $sign = $this->generateSign($probe, $signPassword);
        $decoded = base64_decode(strtr($probe, ['-' => '+', '_' => '/']), true);

        if ($decoded === false || strlen($sign) !== 32 || ! $this->secureCompare($this->generateSign($probe, $signPassword), $sign)) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.paysera_connection_selftest_failed'),
            ];
        }

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

    /**
     * Validate module configuration
     */
    public function validateConfig()
    {
        $required = ['project_id', 'sign_password'];
        $missing = [];

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

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

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

    /**
     * Supported features
     */
    public function getFeatures(): array
    {
        return [
            'refund' => false,
            '3d_secure' => false,
            'save_card' => false,
            'recurring' => false,
            'fraud_check' => false,
            'installment' => false,
        ];
    }

    /**
     * Get configuration fields for admin panel
     */
    public function getConfigFields(): array
    {
        return array_merge(parent::getConfigFields(), [
            'project_id' => [
                'type' => 'text',
                'label' => __('admin/modules.paysera_project_id'),
                'description' => __('admin/modules.paysera_project_id_description'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter Paysera Project ID',
            ],
            'sign_password' => [
                'type' => 'password',
                'label' => __('admin/modules.paysera_sign_password'),
                'description' => __('admin/modules.paysera_sign_password_description'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter Sign Password',
            ],
        ]);
    }

    /**
     * Base64url encode payment data parameters
     *
     * @param  array  $params  Payment parameters to encode
     * @return string Base64url encoded string
     */
    protected function encodeData(array $params): string
    {
        $queryString = http_build_query($params);

        return strtr(base64_encode($queryString), ['+' => '-', '/' => '_']);
    }

    /**
     * Generate outgoing ss1 signature using MD5(data + password) (createRequest WebToPay.php:1156).
     *
     * @param  string  $data  Base64url encoded data
     * @param  string  $password  Sign password from Paysera project settings
     */
    protected function generateSign(string $data, string $password): string
    {
        return md5($data . $password);
    }

    /**
     * Verify callback signature — fail-closed.
     *
     * SS2 (RSA-SHA1, Paysera public key) tercih edilir; imzalı içerik ham
     * base64url `data` string'idir (SS2SignChecker WebToPay.php:2189-2197).
     * SS1 (md5(data+password)) yalnız OpenSSL yoksa fallback (getSigner :1945).
     */
    protected function verifyCallbackSignature(string $data, ?string $ss1, ?string $ss2, ?string $password): bool
    {
        if (function_exists('openssl_verify')) {
            if ($ss2 === null || $ss2 === '') {
                return false; // openssl var ama ss2 yok → fail-closed
            }
            $ss2Binary = base64_decode(strtr($ss2, ['-' => '+', '_' => '/']), true);
            if ($ss2Binary === false || $ss2Binary === '') {
                return false;
            }
            $publicKey = $this->isTestMode() ? $this->publicKeySandbox : $this->publicKeyProd;
            $result = openssl_verify($data, $ss2Binary, $publicKey, OPENSSL_ALGO_SHA1);

            return $result === 1;
        }

        // OpenSSL yoksa SS1 (paylaşılan-sır md5) fallback — secureCompare fail-closed.
        if ($password === null || $password === '' || $ss1 === null || $ss1 === '') {
            return false;
        }

        return $this->secureCompare($this->generateSign($data, $password), $ss1);
    }

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