<?php

namespace App\Modules\Payment\Przelewy24;

use App\Core\Payment\AbstractPayment;

class Przelewy24 extends AbstractPayment
{
    protected $apiUrl;

    public function __construct(array $config = [])
    {
        parent::__construct($config);
        $this->apiUrl = $this->getApiUrl();
    }

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

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

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

    /**
     * Register a transaction via Przelewy24 API and return redirect URL
     */
    public function makePayment(array $params)
    {
        $merchantId = (int) $this->getConfig('merchant_id');
        $posId = (int) $this->getConfig('pos_id', $merchantId);
        $crc = $this->getConfig('crc');

        // Amount must be in grosze (1 PLN = 100 grosze)
        $amount = (int) round($params['amount'] * 100);
        $currency = strtoupper($params['currency'] ?? 'PLN');
        $sessionId = $params['session_id'] ?? $params['order_id'] ?? uniqid('p24_');

        $signData = [
            'sessionId' => $sessionId,
            'merchantId' => $merchantId,
            'amount' => $amount,
            'currency' => $currency,
        ];

        $registerData = [
            'merchantId' => $merchantId,
            'posId' => $posId,
            'sessionId' => $sessionId,
            'amount' => $amount,
            'currency' => $currency,
            'description' => $params['description'] ?? __('admin/modules.przelewy24_payment_description', ['order_id' => $params['order_id'] ?? $sessionId]),
            'email' => $params['customer_email'],
            'urlReturn' => $params['success_url'] ?? $params['redirect_url'] ?? '',
            'urlStatus' => $params['webhook_url'] ?? $params['callback_url'] ?? '',
            'sign' => $this->generateSign($signData, $crc),
        ];

        // Add optional fields
        if (isset($params['customer_name'])) {
            $registerData['client'] = $params['customer_name'];
        }
        if (isset($params['country'])) {
            $registerData['country'] = $params['country'];
        }
        if (isset($params['language'])) {
            $registerData['language'] = $params['language'];
        }

        $response = $this->secureRequest($this->apiUrl . '/transaction/register', 'POST', $registerData);

        if ($response['http_code'] === 200 && isset($response['response']['data']['token'])) {
            $token = $response['response']['data']['token'];
            $redirectUrl = $this->getRedirectBaseUrl() . '/trnRequest/' . $token;

            return [
                'status' => 'redirect',
                'message' => __('admin/modules.przelewy24_payment_created'),
                'transaction_id' => $sessionId,
                'redirect_url' => $redirectUrl,
                'data' => [
                    'token' => $token,
                    'session_id' => $sessionId,
                    'amount' => $params['amount'],
                    'currency' => $currency,
                ],
            ];
        }

        $errorMessage = $response['response']['error'] ?? $response['response']['message'] ?? __('admin/modules.przelewy24_payment_failed');

        return [
            'status' => 'error',
            'message' => $errorMessage,
            'data' => $response,
        ];
    }

    /**
     * Handle payment callback - verify transaction via Przelewy24 API
     */
    public function handlePaymentCallback(array $params)
    {
        $merchantId = (int) $this->getConfig('merchant_id');
        $posId = (int) $this->getConfig('pos_id', $merchantId);
        $crc = $this->getConfig('crc');

        $sessionId = $params['sessionId'] ?? $params['session_id'] ?? null;
        $orderId = $params['orderId'] ?? $params['order_id'] ?? null;
        $amount = (int) ($params['amount'] ?? 0);
        $currency = strtoupper($params['currency'] ?? 'PLN');

        if (! $sessionId || ! $orderId) {
            return [
                'status' => 'failed',
                'message' => __('admin/modules.przelewy24_callback_invalid'),
            ];
        }

        // Defense-in-depth: webhook amount/currency ile beklenen fatura tutarını
        // çapraz doğrula (verify sign amount'u kapsar ama underpayment/mismatch guard).
        if (isset($params['expected_amount'])) {
            $expectedAmount = (int) round($params['expected_amount'] * 100);
            $expectedCurrency = isset($params['expected_currency'])
                ? strtoupper($params['expected_currency']) : $currency;
            if ($amount !== $expectedAmount || $currency !== $expectedCurrency) {
                return [
                    'status' => 'failed',
                    'message' => __('admin/modules.przelewy24_amount_mismatch'),
                ];
            }
        }

        $signData = [
            'sessionId' => $sessionId,
            'orderId' => (int) $orderId,
            'amount' => $amount,
            'currency' => $currency,
        ];

        $verifyData = [
            'merchantId' => $merchantId,
            'posId' => $posId,
            'sessionId' => $sessionId,
            'amount' => $amount,
            'currency' => $currency,
            'orderId' => (int) $orderId,
            'sign' => $this->generateSign($signData, $crc),
        ];

        // P24 REST v1: verify PUT /transaction/verify (HostBill class.przelewy24.php:74).
        $response = $this->secureRequest($this->apiUrl . '/transaction/verify', 'PUT', $verifyData);

        if ($response['http_code'] === 200 && isset($response['response']['data']['status']) && $response['response']['data']['status'] === 'success') {
            return [
                'status' => 'success',
                'message' => __('admin/modules.przelewy24_payment_success'),
                'transaction_id' => $orderId,
                'data' => [
                    'session_id' => $sessionId,
                    'order_id' => $orderId,
                    'amount' => $amount / 100,
                    'currency' => $currency,
                    'przelewy24_status' => 'verified',
                ],
            ];
        }

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

    /**
     * Refund a payment via Przelewy24 API
     */
    public function refundPayment(array $params)
    {
        $transactionId = $params['transaction_id'] ?? $params['order_id'] ?? null;
        $sessionId = $params['session_id'] ?? null;

        if (! $transactionId) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.przelewy24_missing_transaction_id'),
            ];
        }

        // Amount in grosze
        $amount = (int) round(($params['amount'] ?? 0) * 100);

        $refundData = [
            'requestId' => $params['request_id'] ?? uniqid('ref_'),
            'refunds' => [
                [
                    'refundsUuid' => $params['refund_uuid'] ?? \Illuminate\Support\Str::uuid()->toString(),
                    'orderId' => (int) $transactionId,
                    'sessionId' => $sessionId ?? 'refund_' . $transactionId,
                    'amount' => $amount,
                ],
            ],
        ];

        $response = $this->secureRequest($this->apiUrl . '/transaction/refund', 'POST', $refundData);

        if ($response['http_code'] === 200 && isset($response['response']['data'])) {
            $refundResult = $response['response']['data'][0] ?? [];

            // P24 refund status sürüme göre 'success' (string) veya 1 (int) döner
            // (HostBill class.przelewy24.php:108 status==1) — ikisini de kabul et.
            if (isset($refundResult['status']) && in_array($refundResult['status'], ['success', 1, '1'], false)) {
                return [
                    'status' => 'success',
                    'message' => __('admin/modules.przelewy24_refund_success'),
                    'refund_id' => $refundResult['refundsUuid'] ?? $refundData['refunds'][0]['refundsUuid'],
                    'data' => $response['response'],
                ];
            }
        }

        $errorMessage = $response['response']['error'] ?? $response['response']['message'] ?? __('admin/modules.przelewy24_refund_failed');

        return [
            'status' => 'error',
            'message' => $errorMessage,
            'data' => $response,
        ];
    }

    /**
     * Generate a payment link - same as makePayment, return redirect URL
     */
    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 API connection by calling /testAccess endpoint
     */
    public function testConnection(array $params = [])
    {
        $response = $this->secureRequest($this->apiUrl . '/testAccess', 'GET');

        if ($response['http_code'] === 200 && ($response['response']['data'] ?? null) === true) {
            return [
                'status' => 'success',
                'message' => __('admin/modules.przelewy24_connection_success'),
            ];
        }

        $errorMessage = $response['response']['error'] ?? __('admin/modules.przelewy24_connection_failed');

        return [
            'status' => 'error',
            'message' => $errorMessage,
            'data' => $response,
        ];
    }

    /**
     * Validate module configuration
     */
    public function validateConfig()
    {
        $required = ['merchant_id', 'pos_id', 'api_key', 'crc'];
        $missing = [];

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

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

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

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

    /**
     * Return supported features (alias)
     */
    public function getSupportedFeatures(): array
    {
        return $this->getFeatures();
    }

    /**
     * Get configuration fields for admin panel
     */
    public function getConfigFields(): array
    {
        return array_merge(parent::getConfigFields(), [
            'merchant_id' => [
                'type' => 'text',
                'label' => __('admin/modules.przelewy24_merchant_id'),
                'description' => __('admin/modules.przelewy24_merchant_id_description'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter Merchant ID',
            ],
            'pos_id' => [
                'type' => 'text',
                'label' => __('admin/modules.przelewy24_pos_id'),
                'description' => __('admin/modules.przelewy24_pos_id_description'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter POS ID (usually same as Merchant ID)',
            ],
            'api_key' => [
                'type' => 'password',
                'label' => __('admin/modules.przelewy24_api_key'),
                'description' => __('admin/modules.przelewy24_api_key_description'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter API Key',
            ],
            'crc' => [
                'type' => 'password',
                'label' => __('admin/modules.przelewy24_crc'),
                'description' => __('admin/modules.przelewy24_crc_description'),
                'required' => true,
                'value' => '',
                'placeholder' => 'Enter CRC Key',
            ],
        ]);
    }

    /**
     * Override default headers for Basic Auth (pos_id:api_key)
     */
    protected function getDefaultHeaders()
    {
        $posId = $this->getConfig('pos_id', $this->getConfig('merchant_id', ''));
        $apiKey = $this->getConfig('api_key', '');
        $credentials = base64_encode($posId . ':' . $apiKey);

        return [
            'Content-Type: application/json',
            'Accept: application/json',
            'User-Agent: ProCP/1.0 Payment Gateway Module',
            'Authorization: Basic ' . $credentials,
        ];
    }

    /**
     * Get API URL based on test mode
     */
    protected function getApiUrl(): string
    {
        return $this->isTestMode()
            ? 'https://sandbox.przelewy24.pl/api/v1'
            : 'https://secure.przelewy24.pl/api/v1';
    }

    /**
     * Get redirect base URL based on test mode
     */
    protected function getRedirectBaseUrl(): string
    {
        return $this->isTestMode()
            ? 'https://sandbox.przelewy24.pl'
            : 'https://secure.przelewy24.pl';
    }

    /**
     * Hardened JSON transport for P24 (TLS-verify + timeout + protocol lock,
     * PRC-888 aligned) with arbitrary HTTP method — verify requires PUT which
     * global postJson()/callApi() cannot express. Same return envelope.
     *
     * @return array{http_code:int,response:mixed,raw_response:string,error:?string}
     */
    protected function secureRequest(string $url, string $method = 'POST', array $data = []): array
    {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL             => $url,
            CURLOPT_RETURNTRANSFER  => true,
            CURLOPT_CUSTOMREQUEST   => strtoupper($method),
            CURLOPT_HTTPHEADER      => $this->getDefaultHeaders(),
            CURLOPT_SSL_VERIFYPEER  => true,
            CURLOPT_SSL_VERIFYHOST  => 2,
            CURLOPT_TIMEOUT         => 30,
            CURLOPT_CONNECTTIMEOUT  => 10,
            CURLOPT_PROTOCOLS       => CURLPROTO_HTTPS | CURLPROTO_HTTP,
            CURLOPT_REDIR_PROTOCOLS => CURLPROTO_HTTPS | CURLPROTO_HTTP,
        ]);

        if (strtoupper($method) !== 'GET' && ! empty($data)) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }

        $response = curl_exec($ch);
        $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        return [
            'http_code'    => $httpCode,
            'response'     => json_decode((string) $response, true),
            'raw_response' => $response === false ? '' : (string) $response,
            'error'        => $error !== '' ? $error : null,
        ];
    }

    /**
     * Generate SHA384 sign for Przelewy24 API requests
     *
     * @param  array  $data  Key-value pairs to include in sign
     * @param  string  $crc  CRC key
     * @return string SHA384 hash
     */
    protected function generateSign(array $data, string $crc): string
    {
        $data['crc'] = $crc;

        return hash('sha384', json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    }
}
