<?php
if (!defined('BASE_PATH')) { define('BASE_PATH', dirname(dirname(__DIR__))); }
require_once BASE_PATH . '/database/connection.php';

class Key2PayClient {
    private $pdo;
    private $apiBaseUrl = 'https://api.key2pay.io/v1';
    private $username;
    private $password;
    private $accessToken;
    private $tokenExpiresAt;
    private $ipnUrl;
    private $successUrl;
    private $cancelUrl;
    private $currency = 'USD';
    private $authHeaderPrefix = 'Bearer';
    private $authHeaderPrefixPayment = 'Bearer';

    public function __construct($pdo = null) {
        $this->pdo = $pdo ?: Database::getInstance()->getConnection();
        $this->loadConfiguration();
    }

    private function ensurePaymentMethodsTable() {
        try {
            $this->pdo->exec("CREATE TABLE IF NOT EXISTS payment_methods (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(64) NOT NULL, display_name VARCHAR(128) NOT NULL, provider_key VARCHAR(64) NOT NULL, api_category VARCHAR(64) NOT NULL DEFAULT 'Payment Method', category VARCHAR(32) NOT NULL, type ENUM('deposit','withdraw','both') NOT NULL DEFAULT 'deposit', logo_path VARCHAR(255) NULL, config JSON NULL, is_active TINYINT(1) NOT NULL DEFAULT 1, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
            try { $this->pdo->exec("ALTER TABLE payment_methods ADD COLUMN api_base_url VARCHAR(255) NULL"); } catch (Throwable $__) {}
            try { $this->pdo->exec("ALTER TABLE payment_methods ADD COLUMN api_username VARCHAR(128) NULL"); } catch (Throwable $__) {}
            try { $this->pdo->exec("ALTER TABLE payment_methods ADD COLUMN api_password VARCHAR(128) NULL"); } catch (Throwable $__) {}
            try { $this->pdo->exec("ALTER TABLE payment_methods ADD COLUMN api_token VARCHAR(255) NULL"); } catch (Throwable $__) {}
            try { $this->pdo->exec("ALTER TABLE payment_methods ADD COLUMN api_ipn_url VARCHAR(255) NULL"); } catch (Throwable $__) {}
            try { $this->pdo->exec("ALTER TABLE payment_methods ADD COLUMN api_success_url VARCHAR(255) NULL"); } catch (Throwable $__) {}
            try { $this->pdo->exec("ALTER TABLE payment_methods ADD COLUMN api_cancel_url VARCHAR(255) NULL"); } catch (Throwable $__) {}
            try { $this->pdo->exec("ALTER TABLE payment_methods ADD COLUMN api_currency VARCHAR(10) NULL"); } catch (Throwable $__) {}
        } catch (Throwable $e) {}
    }

    private function loadConfiguration() {
        $this->ensurePaymentMethodsTable();
        try {
            $sel = $this->pdo->prepare("SELECT api_base_url, api_username, api_password, api_token, api_ipn_url, api_success_url, api_cancel_url, api_currency FROM payment_methods WHERE provider_key='key2pay' AND is_active=1 AND (type='deposit' OR type='both') ORDER BY id DESC LIMIT 1");
            $sel->execute();
            if ($pm = $sel->fetch()) {
                $this->apiBaseUrl = $pm['api_base_url'] ?: $this->apiBaseUrl;
                $this->username = $pm['api_username'] ?: $this->username;
                $this->password = $pm['api_password'] ?: $this->password;
                $this->accessToken = $pm['api_token'] ?: $this->accessToken;
                $this->ipnUrl = $pm['api_ipn_url'] ?: $this->ipnUrl;
                $this->successUrl = $pm['api_success_url'] ?: $this->successUrl;
                $this->cancelUrl = $pm['api_cancel_url'] ?: $this->cancelUrl;
                $this->currency = $pm['api_currency'] ?: $this->currency;
            }
            $stmt = $this->pdo->prepare("SELECT setting_key, setting_value FROM integration_settings WHERE integration_name = 'key2pay'");
            $stmt->execute();
            while ($row = $stmt->fetch()) {
                switch ($row['setting_key']) {
                    case 'api_base_url': $this->apiBaseUrl = $this->apiBaseUrl ?: $row['setting_value']; break;
                    case 'username': $this->username = $this->username ?: $row['setting_value']; break;
                    case 'password': $this->password = $this->password ?: $row['setting_value']; break;
                    case 'access_token': $this->accessToken = $this->accessToken ?: $row['setting_value']; break;
                    case 'token_expires_at': $this->tokenExpiresAt = $this->tokenExpiresAt ?: $row['setting_value']; break;
                    case 'ipn_url': $this->ipnUrl = $this->ipnUrl ?: $row['setting_value']; break;
                    case 'success_url': $this->successUrl = $this->successUrl ?: $row['setting_value']; break;
                    case 'cancel_url': $this->cancelUrl = $this->cancelUrl ?: $row['setting_value']; break;
                    case 'currency': $this->currency = $row['setting_value'] ?: $this->currency; break;
                    case 'auth_header_prefix':
                        $val = trim($row['setting_value']);
                        if ($val !== '') { $this->authHeaderPrefix = $val; }
                        break;
                    case 'auth_header_prefix_payment':
                        $val = trim($row['setting_value']);
                        if ($val !== '') { $this->authHeaderPrefixPayment = $val; }
                        break;
                }
            }
            // Fallback: usar credenciales de Big4pay si Key2Pay no tiene usuario/clave
            if (empty($this->username) || empty($this->password)) {
                try {
                    $selB = $this->pdo->prepare("SELECT api_username, api_password FROM payment_methods WHERE provider_key='big4pay' AND is_active=1 AND (type='deposit' OR type='both') ORDER BY id DESC LIMIT 1");
                    $selB->execute();
                    if ($pmB = $selB->fetch()) {
                        $this->username = $this->username ?: ($pmB['api_username'] ?? '');
                        $this->password = $this->password ?: ($pmB['api_password'] ?? '');
                    }
                } catch (Throwable $__) {}
                try {
                    $stmtB = $this->pdo->prepare("SELECT setting_key, setting_value FROM integration_settings WHERE integration_name = 'big4pay'");
                    $stmtB->execute();
                    while ($row = $stmtB->fetch()) {
                        if ($row['setting_key'] === 'username' && empty($this->username)) { $this->username = $row['setting_value']; }
                        if ($row['setting_key'] === 'password' && empty($this->password)) { $this->password = $row['setting_value']; }
                    }
                } catch (Throwable $__) {}
            }
            // Fallback base URL si no definida
            if (empty($this->apiBaseUrl)) { $this->apiBaseUrl = 'https://api.key2pay.io/v1'; }
        } catch (Throwable $e) {}
    }

    public function isConfigured() {
        return !empty($this->apiBaseUrl) && !empty($this->username) && !empty($this->password);
    }

    public function saveConfiguration($apiBaseUrl, $username, $password, $currency = null, $extra = []) {
        $this->ensurePaymentMethodsTable();
        try {
            $sel = $this->pdo->prepare("SELECT id FROM payment_methods WHERE provider_key='key2pay' AND is_active=1 AND (type='deposit' OR type='both') ORDER BY id DESC LIMIT 1");
            $sel->execute();
            $row = $sel->fetch();
            if ($row) {
                $upd = $this->pdo->prepare("UPDATE payment_methods SET api_base_url=?, api_username=?, api_password=?, api_currency=COALESCE(?, api_currency), api_ipn_url=COALESCE(?, api_ipn_url), api_success_url=COALESCE(?, api_success_url), api_cancel_url=COALESCE(?, api_cancel_url) WHERE id=?");
                $upd->execute([$apiBaseUrl, $username, $password, ($currency ?? null), ($extra['ipn_url'] ?? null), ($extra['success_url'] ?? null), ($extra['cancel_url'] ?? null), (int)$row['id']]);
            } else {
                $ins = $this->pdo->prepare("INSERT INTO payment_methods (name, display_name, provider_key, api_category, category, type, is_active, api_base_url, api_username, api_password, api_currency, api_ipn_url, api_success_url, api_cancel_url) VALUES ('Key2Pay','Key2Pay','key2pay','Payment Method','Payment Method','deposit',1, ?, ?, ?, ?, ?, ?, ?)");
                $ins->execute([$apiBaseUrl, $username, $password, ($currency ?? $this->currency), ($extra['ipn_url'] ?? null), ($extra['success_url'] ?? null), ($extra['cancel_url'] ?? null)]);
            }
            $this->apiBaseUrl = $apiBaseUrl ?: $this->apiBaseUrl;
            $this->username = $username ?: $this->username;
            $this->password = $password ?: $this->password;
            if (!empty($currency)) { $this->currency = $currency; }
            $this->ipnUrl = ($extra['ipn_url'] ?? $this->ipnUrl);
            $this->successUrl = ($extra['success_url'] ?? $this->successUrl);
            $this->cancelUrl = ($extra['cancel_url'] ?? $this->cancelUrl);
            return true;
        } catch (Throwable $e) { return false; }
    }

    public function saveAccessToken($token, $expiresInSeconds) {
        if (empty($token)) return false;
        try {
            $stmtDel = $this->pdo->prepare("DELETE FROM integration_settings WHERE integration_name='key2pay' AND setting_key IN ('access_token','token_expires_at')");
            $stmtDel->execute();
            $stmtIns = $this->pdo->prepare("INSERT INTO integration_settings (integration_name, setting_key, setting_value) VALUES ('key2pay','access_token',?), ('key2pay','token_expires_at',?)");
            $expiresAt = (string)(time() + (int)$expiresInSeconds);
            $stmtIns->execute([$token, $expiresAt]);
            $this->accessToken = $token;
            $this->tokenExpiresAt = $expiresAt;
            $upd = $this->pdo->prepare("UPDATE payment_methods SET api_token=? WHERE provider_key='key2pay' AND is_active=1 AND (type='deposit' OR type='both')");
            $upd->execute([$token]);
            return true;
        } catch (Throwable $e) { return false; }
    }

    public function createAccessToken() {
        if (!$this->isConfigured()) { return ['success'=>false,'message'=>'Key2Pay no está configurado']; }
        $url = rtrim($this->apiBaseUrl, '/') . '/auth/token';
        $basic = base64_encode($this->username . ':' . $this->password);
        $attempts = [
            [ 'headers' => [ 'Content-Type: application/json', 'Accept: application/json', 'User-Agent: ProfixCRM/1.0' ], 'body' => json_encode([ 'apiKey'=>$this->username, 'secretKey'=>$this->password ]) ],
            [ 'headers' => [ 'Content-Type: application/x-www-form-urlencoded', 'Accept: application/json', 'User-Agent: ProfixCRM/1.0' ], 'body' => http_build_query([ 'username'=>$this->username, 'password'=>$this->password ]) ],
            [ 'headers' => [ 'Accept: application/json', 'User-Agent: ProfixCRM/1.0', 'Authorization: Basic ' . $basic ], 'body' => '' ]
        ];
        $last = null;
        foreach ($attempts as $a) {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $a['body']);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $a['headers']);
            curl_setopt($ch, CURLOPT_TIMEOUT, 20);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            $body = curl_exec($ch);
            $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $err = curl_error($ch);
            curl_close($ch);
            $json = json_decode($body, true);
            $last = [ 'success'=>(!$err && $code>=200 && $code<300), 'status'=>$code, 'body'=>$body, 'json'=>$json ?? null, 'message'=>$err ? ('Error de conexión: '.$err) : null ];
            if ($last['success'] && is_array($json)) {
                $token = $json['accessToken'] ?? $json['access_token'] ?? null;
                $expiresIn = $json['expiresIn'] ?? 3600;
                if ($token) { $this->saveAccessToken($token, $expiresIn); }
                break;
            }
        }
        return $last ?? ['success'=>false,'status'=>null,'body'=>null];
    }

    public function getConfiguration() {
        return [ 'api_base_url'=>$this->apiBaseUrl, 'username'=>$this->username, 'configured'=>$this->isConfigured(), 'currency'=>$this->currency, 'ipn_url'=>$this->ipnUrl, 'success_url'=>$this->successUrl, 'cancel_url'=>$this->cancelUrl, 'access_token'=>$this->accessToken ];
    }

    public function createPayment($params) {
        $url = rtrim($this->apiBaseUrl, '/') . '/payments';
        $now = time();
        $token = $this->accessToken;
        $override = isset($params['access_token_override']) ? trim((string)$params['access_token_override']) : '';
        if ($override !== '') { $token = $override; }
        if (empty($token) || (!empty($this->tokenExpiresAt) && (int)$this->tokenExpiresAt <= $now)) {
            $tokRes = $this->createAccessToken();
            if (!empty($tokRes['json']['accessToken'])) { $token = $tokRes['json']['accessToken']; }
        }
        $amountMinor = (int)($params['amount'] ?? 0);
        $custIn = $params['customer'] ?? [];
        $phone = $custIn['phone'] ?? '';
        $customer = [
            'firstName' => $custIn['FirstName'] ?? $custIn['firstName'] ?? $custIn['first_name'] ?? '',
            'lastName' => $custIn['LastName'] ?? $custIn['lastName'] ?? $custIn['last_name'] ?? '',
            'email' => $custIn['Email'] ?? $custIn['email'] ?? '',
            'mobile' => $custIn['Mobile'] ?? $custIn['mobile'] ?? $phone,
            'phone' => $phone,
            'country' => strtoupper($custIn['Country'] ?? $custIn['country'] ?? ''),
            'city' => $custIn['city'] ?? '',
            'postcode' => $custIn['postcode'] ?? '',
            'personalId' => $custIn['personalId'] ?? '',
            'ip' => $custIn['ip'] ?? ''
        ];
        $payload = [
            'paymentMethodId' => (string)($params['paymentMethodId'] ?? ''),
            'channel' => strtoupper($params['channel'] ?? 'ONLINE'),
            'amount' => $amountMinor,
            'currency' => strtoupper($params['currency'] ?? $this->currency),
            'language' => strtoupper($params['language'] ?? 'EN'),
            'orderId' => $params['order_id'] ?? $this->generateIdentifier(),
            'notificationUrl' => $params['notificationUrl'] ?? null,
            'returnUrl' => $params['returnUrl'] ?? $this->successUrl,
            'cancelUrl' => $params['cancelUrl'] ?? $this->cancelUrl,
            'customer' => $customer
        ];
        if (!isset($params['description'])) { /* omit description */ } else { $payload['description'] = $params['description']; }
        if (!empty($payload['notificationUrl']) && stripos($payload['notificationUrl'], 'https://') !== 0) { unset($payload['notificationUrl']); }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
        curl_setopt($ch, CURLOPT_ENCODING, '');
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        $headers = [ 'Content-Type: application/json', 'Accept: application/json', 'User-Agent: ProfixCRM/1.0' ];
        if (!empty($token)) {
            $prefixed = (stripos($token, 'Bearer ') === 0 || stripos($token, 'Basic ') === 0);
            $authValue = $prefixed ? $token : ($this->authHeaderPrefixPayment === 'raw' ? $token : ($this->authHeaderPrefixPayment . ' ' . $token));
            $headers[] = 'Authorization: ' . $authValue;
        }
        $headersMasked = [];
        foreach ($headers as $h) {
            if (stripos($h, 'Authorization:') === 0) {
                $parts = explode(' ', $h, 3);
                if (count($parts) >= 2) {
                    $scheme = $parts[1];
                    $tokenStr = isset($parts[2]) ? $parts[2] : '';
                    if ($scheme && $tokenStr) {
                        $mask = substr($tokenStr, 0, 6) . '***';
                        $headersMasked[] = 'Authorization: ' . $scheme . ' ' . $mask;
                        $authHeaderPrefixUsed = $scheme;
                        $authTokenPreview = substr($tokenStr, 0, 12) . '...' . substr($tokenStr, -6);
                        $authTokenLen = strlen($tokenStr);
                        $jwtExp = null; $jwtIss = null; $jwtSub = null; $jwtAud = null;
                        $seg = explode('.', $tokenStr);
                        if (count($seg) >= 2) {
                            $payloadRaw = base64_decode(strtr($seg[1], '-_', '+/'));
                            if ($payloadRaw) {
                                $payloadArr = json_decode($payloadRaw, true);
                                if (is_array($payloadArr)) {
                                    $jwtExp = $payloadArr['exp'] ?? null;
                                    $jwtIss = $payloadArr['iss'] ?? null;
                                    $jwtSub = $payloadArr['sub'] ?? null;
                                    $jwtAud = $payloadArr['aud'] ?? null;
                                }
                            }
                        }
                        continue;
                    }
                }
                $headersMasked[] = 'Authorization: ******';
            } else {
                $headersMasked[] = $h;
            }
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $resp = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $hdrSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $err = curl_error($ch);
        curl_close($ch);
        if ($err) return ['success'=>false,'http_code'=>null,'body'=>null,'message'=>'Error de conexión: '.$err, 'request_url'=>$url, 'request_headers'=>$headersMasked, 'auth_token_preview'=>($authTokenPreview ?? null), 'auth_token_len'=>($authTokenLen ?? null), 'auth_header_prefix'=>($authHeaderPrefixUsed ?? null), 'jwt_exp'=>($jwtExp ?? null), 'jwt_iss'=>($jwtIss ?? null), 'jwt_sub'=>($jwtSub ?? null), 'jwt_aud'=>($jwtAud ?? null)];
        $body = substr($resp, $hdrSize);
        $json = null; if (is_string($body)) { $json = json_decode($body, true); }
        // Map checkout/redirect URL
        $redirectUrl = null;
        if (is_array($json)) {
            $redirectUrl = $json['redirect_url'] ?? $json['checkout_url'] ?? $json['payment_link'] ?? $json['paymentLink'] ?? $json['payment_page_url'] ?? $json['paymentPageUrl'] ?? $json['url'] ?? null;
            if (!$redirectUrl) {
                $stack = [$json];
                while ($stack) {
                    $cur = array_shift($stack);
                    foreach ($cur as $k => $v) {
                        if (is_array($v)) { $stack[] = $v; continue; }
                        if (is_string($v)) {
                            $kk = strtolower((string)$k);
                            $isCandidate = (strpos($kk,'url')!==false || strpos($kk,'link')!==false || strpos($kk,'checkout')!==false || strpos($kk,'payment')!==false);
                            if ($isCandidate && (strpos($v,'http://')===0 || strpos($v,'https://')===0)) { $redirectUrl = $v; break 2; }
                        }
                    }
                }
            }
        }
        return [ 'success'=>($code>=200&&$code<300), 'http_code'=>$code, 'body'=>$body, 'json'=>$json, 'redirect_url'=>$redirectUrl, 'checkout_url'=>($json['checkout_url'] ?? null), 'auth_used'=>!empty($token), 'request_url'=>$url, 'request_headers'=>$headersMasked, 'auth_token_preview'=>($authTokenPreview ?? null), 'auth_token_len'=>($authTokenLen ?? null), 'auth_header_prefix'=>($authHeaderPrefixUsed ?? null), 'jwt_exp'=>($jwtExp ?? null), 'jwt_iss'=>($jwtIss ?? null), 'jwt_sub'=>($jwtSub ?? null), 'jwt_aud'=>($jwtAud ?? null) ];
    }

    public function createPaymentRaw($payload, $refreshToken = true) {
        $url = rtrim($this->apiBaseUrl, '/') . '/payments';
        $token = $this->accessToken;
        if ($refreshToken) {
            $tokRes = $this->createAccessToken();
            if (!empty($tokRes['json']['accessToken'])) { $token = $tokRes['json']['accessToken']; }
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
        curl_setopt($ch, CURLOPT_ENCODING, '');
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        $headers = [ 'Content-Type: application/json', 'Accept: application/json', 'User-Agent: ProfixCRM/1.0' ];
        if (!empty($token)) {
            $prefixed = (stripos($token, 'Bearer ') === 0 || stripos($token, 'Basic ') === 0);
            $authValue = $prefixed ? $token : ($this->authHeaderPrefixPayment . ' ' . $token);
            $headers[] = 'Authorization: ' . $authValue;
        }
        $headersMasked = [];
        foreach ($headers as $h) {
            if (stripos($h, 'Authorization:') === 0) {
                $parts = explode(' ', $h, 3);
                if (count($parts) >= 2) {
                    $scheme = $parts[1];
                    $tokenStr = isset($parts[2]) ? $parts[2] : '';
                    $mask = substr($tokenStr, 0, 6) . '***';
                    $headersMasked[] = 'Authorization: ' . $scheme . ' ' . $mask;
                } else { $headersMasked[] = 'Authorization: ******'; }
            } else { $headersMasked[] = $h; }
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $resp = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $hdrSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $err = curl_error($ch);
        curl_close($ch);
        if ($err) return ['success'=>false,'http_code'=>null,'body'=>null,'message'=>'Error de conexión: '.$err, 'request_url'=>$url, 'request_headers'=>$headersMasked];
        $body = substr($resp, $hdrSize);
        $json = null; if (is_string($body)) { $json = json_decode($body, true); }
        $redirectUrl = null;
        if (is_array($json)) {
            $redirectUrl = $json['redirect_url'] ?? $json['checkout_url'] ?? $json['payment_link'] ?? $json['paymentLink'] ?? $json['payment_page_url'] ?? $json['paymentPageUrl'] ?? $json['url'] ?? null;
            if (!$redirectUrl) {
                $stack = [$json];
                while ($stack) {
                    $cur = array_shift($stack);
                    foreach ($cur as $k => $v) {
                        if (is_array($v)) { $stack[] = $v; continue; }
                        if (is_string($v)) {
                            $kk = strtolower((string)$k);
                            $isCandidate = (strpos($kk,'url')!==false || strpos($kk,'link')!==false || strpos($kk,'checkout')!==false || strpos($kk,'payment')!==false);
                            if ($isCandidate && (strpos($v,'http://')===0 || strpos($v,'https://')===0)) { $redirectUrl = $v; break 2; }
                        }
                    }
                }
            }
        }
        return [ 'success'=>($code>=200&&$code<300), 'http_code'=>$code, 'body'=>$body, 'json'=>$json, 'redirect_url'=>$redirectUrl, 'checkout_url'=>($json['checkout_url'] ?? null), 'auth_used'=>!empty($token), 'request_url'=>$url, 'request_headers'=>$headersMasked ];
    }

    public function getPaymentMethods($params = []) {
        $url = rtrim($this->apiBaseUrl, '/') . '/payment-methods';
        $qs = [];
        foreach (['channel','country','currency'] as $k) {
            if (!empty($params[$k])) { $qs[$k] = $params[$k]; }
        }
        if (!empty($qs)) { $url .= '?' . http_build_query($qs); }
        $token = $this->accessToken;
        $now = time();
        if (empty($token) || (!empty($this->tokenExpiresAt) && (int)$this->tokenExpiresAt <= $now)) {
            $tokRes = $this->createAccessToken();
            if (!empty($tokRes['json']['accessToken'])) { $token = $tokRes['json']['accessToken']; }
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        $headers = [ 'Accept: application/json', 'User-Agent: ProfixCRM/1.0' ];
        if (!empty($token)) {
            $prefixed = (stripos($token, 'Bearer ') === 0 || stripos($token, 'Basic ') === 0);
            $authValue = $prefixed ? $token : ($this->authHeaderPrefix === 'raw' ? $token : ($this->authHeaderPrefix . ' ' . $token));
            $headers[] = 'Authorization: ' . $authValue;
        }
        $headersMasked = [];
        foreach ($headers as $h) {
            if (stripos($h, 'Authorization:') === 0) {
                $parts = explode(' ', $h, 3);
                if (count($parts) >= 2) {
                    $scheme = $parts[1];
                    $tokenStr = isset($parts[2]) ? $parts[2] : '';
                    $mask = substr($tokenStr, 0, 6) . '***';
                    $headersMasked[] = 'Authorization: ' . $scheme . ' ' . $mask;
                    continue;
                }
                $headersMasked[] = 'Authorization: ******';
            } else {
                $headersMasked[] = $h;
            }
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_TIMEOUT, 20);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $resp = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $hdrSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $err = curl_error($ch);
        curl_close($ch);
        if ($err) return ['success'=>false,'http_code'=>null,'body'=>null,'message'=>'Error de conexión: '.$err, 'request_url'=>$url, 'request_headers'=>$headersMasked];
        $body = substr($resp, $hdrSize);
        $json = null; if (is_string($body)) { $json = json_decode($body, true); }
        return [ 'success'=>($code>=200 && $code<300), 'http_code'=>$code, 'body'=>$body, 'json'=>$json, 'request_url'=>$url, 'request_headers'=>$headersMasked ];
    }

    public function generateIdentifier() {
        try {
            $this->pdo->beginTransaction();
            $stmtSel = $this->pdo->prepare("SELECT setting_value FROM integration_settings WHERE integration_name = 'key2pay' AND setting_key = 'order_counter' LIMIT 1");
            $stmtSel->execute();
            $row = $stmtSel->fetch();
            $counter = $row ? (int)$row['setting_value'] : 0;
            $counter++;
            $this->pdo->prepare("DELETE FROM integration_settings WHERE integration_name='key2pay' AND setting_key='order_counter'")->execute();
            $this->pdo->prepare("INSERT INTO integration_settings (integration_name, setting_key, setting_value) VALUES ('key2pay','order_counter', ?)")->execute([$counter]);
            $this->pdo->commit();
            return 'ORD_' . str_pad((string)$counter, 8, '0', STR_PAD_LEFT);
        } catch (Throwable $e) {
            $this->pdo->rollBack();
            $fallback = (int)(microtime(true) * 1000) % 100000000;
            return 'ORD_' . str_pad((string)$fallback, 8, '0', STR_PAD_LEFT);
        }
    }

    public function createCheckoutPage($params) {
        $url = rtrim($this->apiBaseUrl, '/') . '/checkout-pages';
        $token = $this->accessToken;
        $now = time();
        if (empty($token) || (!empty($this->tokenExpiresAt) && (int)$this->tokenExpiresAt <= $now)) {
            $tokRes = $this->createAccessToken();
            if (!empty($tokRes['json']['accessToken'])) { $token = $tokRes['json']['accessToken']; }
        }
        $amountMinor = isset($params['amount']) ? (int)$params['amount'] : 0; // ya debe venir en unidades menores
        $custIn = $params['customer'] ?? [];
        $customer = [
            'FirstName' => $custIn['FirstName'] ?? $custIn['firstName'] ?? $custIn['first_name'] ?? '',
            'LastName' => $custIn['LastName'] ?? $custIn['lastName'] ?? $custIn['last_name'] ?? '',
            'Email' => $custIn['Email'] ?? $custIn['email'] ?? '',
            'Mobile' => $custIn['Mobile'] ?? $custIn['mobile'] ?? ''
        ];
        $payload = [
            'currency' => strtoupper($params['currency'] ?? $this->currency),
            'amount' => $amountMinor,
            'language' => strtoupper($params['language'] ?? 'EN'),
            'orderId' => $params['orderId'] ?? $this->generateIdentifier(),
            'description' => $params['description'] ?? 'Deposit',
            'notificationUrl' => $params['notificationUrl'] ?? $this->ipnUrl,
            'returnUrl' => $params['returnUrl'] ?? $this->successUrl,
            'cancelUrl' => $params['cancelUrl'] ?? $this->cancelUrl,
            'customer' => $customer
        ];
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        $headers = [ 'Content-Type: application/json', 'Accept: application/json', 'User-Agent: ProfixCRM/1.0' ];
        if (!empty($token)) { $headers[] = 'Authorization: Bearer ' . $token; }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $resp = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $hdrSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $err = curl_error($ch);
        curl_close($ch);
        if ($err) return [ 'success'=>false, 'http_code'=>null, 'body'=>null, 'message'=>'Error de conexión: '.$err ];
        $body = substr($resp, $hdrSize);
        $json = null; if (is_string($body)) { $json = json_decode($body, true); }
        // Persistir intento
        try {
            $this->pdo->exec("CREATE TABLE IF NOT EXISTS payment_attempts (
              id INT AUTO_INCREMENT PRIMARY KEY,
              client_id INT NULL,
              account_number VARCHAR(64) NULL,
              method VARCHAR(64) NOT NULL,
              identifier VARCHAR(64) NOT NULL,
              amount DECIMAL(18,6) NOT NULL,
              currency VARCHAR(8) NOT NULL,
              status VARCHAR(32) NOT NULL,
              external_transaction_id VARCHAR(128) NULL,
              source VARCHAR(32) NOT NULL,
              redirect_url VARCHAR(255) NULL,
              checkout_url VARCHAR(255) NULL,
              message TEXT NULL,
              raw_json JSON NULL,
              created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
              updated_at DATETIME NULL,
              UNIQUE KEY uniq_identifier (identifier)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
            $identifier = $payload['orderId'];
            $clientId = isset($params['client_id']) ? (int)$params['client_id'] : null;
            $accNum = $params['account_number'] ?? null;
            $checkoutUrl = $json['paymentPageUrl'] ?? $json['paymentFormUrl'] ?? null;
            $checkSel = $this->pdo->prepare("SELECT id FROM payment_attempts WHERE identifier = ? LIMIT 1");
            $checkSel->execute([$identifier]);
            if (!$checkSel->fetch()) {
                $ins = $this->pdo->prepare("INSERT INTO payment_attempts (client_id, account_number, method, identifier, amount, currency, status, source, checkout_url, raw_json) VALUES (?,?,?,?,?,?, 'created', 'key2pay', ?, ?)");
                $ins->execute([$clientId, $accNum, 'key2pay', $identifier, ($amountMinor/100.0), $payload['currency'], $checkoutUrl, json_encode($json)]);
            }
        } catch (Throwable $__) {}
        return [ 'success'=>($code>=200 && $code<300), 'http_code'=>$code, 'body'=>$body, 'json'=>$json ];
    }

    public function getCheckoutPage($uid) {
        $url = rtrim($this->apiBaseUrl, '/') . '/checkout-pages/' . urlencode($uid);
        $token = $this->accessToken;
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        $headers = [ 'Accept: application/json', 'User-Agent: ProfixCRM/1.0' ];
        if (!empty($token)) { $headers[] = 'Authorization: Bearer ' . $token; }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_TIMEOUT, 20);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $resp = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $hdrSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $err = curl_error($ch);
        curl_close($ch);
        if ($err) return [ 'success'=>false, 'http_code'=>null, 'body'=>null, 'message'=>'Error de conexión: '.$err ];
        $body = substr($resp, $hdrSize);
        $json = null; if (is_string($body)) { $json = json_decode($body, true); }
        return [ 'success'=>($code>=200 && $code<300), 'http_code'=>$code, 'body'=>$body, 'json'=>$json ];
    }
}
