<?php
/**
 * (c) ININOUT & PYXIS. All Rights Reserved.
 * Wszelkie modyfikacje tego pliku wymagaja zgloszenia oraz zgody autorow.
 * Any modifications to this file require notification and consent of the authors.
 */
/**
 * i-BOK 5 - Inicjalizacja płatności online
 *
 * Standalone (poza routerem). Wymaga aktywnej sesji klienta + CSRF.
 * POST: gateway, invoice_nr, kwota
 */
error_reporting(0);

require_once __DIR__ . '/config.php';
require_once __DIR__ . '/inc/session.php';
require_once __DIR__ . '/inc/security.php';
require_once __DIR__ . '/inc/auth.php';
require_once __DIR__ . '/inc/functions.php';
require_once __DIR__ . '/inc/vbk_reader.php';
require_once __DIR__ . '/inc/payment.php';
require_once __DIR__ . '/lang/loader.php';
load_language();

// Sprawdź sesję klienta
if (!is_client_logged_in()) {
    header('Location: index.php');
    exit;
}

// Tylko POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    header('Location: index.php?page=faktury');
    exit;
}

// CSRF
if (!csrf_validate()) {
    header('Location: index.php?page=faktury&error=csrf');
    exit;
}

$gateway = trim($_POST['gateway'] ?? '');
$invoice_nr = trim($_POST['invoice_nr'] ?? '');
$kwota = trim($_POST['kwota'] ?? '');
$client_id = $_SESSION['client_id'];

// Tryb demo — płatności online niedostępne
if (ibok_is_demo()) {
    payment_log("Demo: płatność zablokowana (klient: {$client_id})");
    header('Location: index.php?page=faktury&error=demo');
    exit;
}

// Walidacja bramki
$allowed_gateways = ['tpay', 'p24', 'payu'];
if (!in_array($gateway, $allowed_gateways)) {
    payment_log("BŁĄD: Nieprawidłowa bramka '{$gateway}' (klient: {$client_id})");
    header('Location: index.php?page=faktury&error=gateway');
    exit;
}

// Wczytaj konfigurację
$cfg = payment_load_config($gateway);
if (empty($cfg['enabled'])) {
    payment_log("BŁĄD: Bramka '{$gateway}' wyłączona (klient: {$client_id})");
    header('Location: index.php?page=faktury&error=disabled');
    exit;
}

// Walidacja kwoty
$kwota = str_replace(',', '.', $kwota);
$amount = (float)$kwota;
if ($amount <= 0 || $amount > 999999.99) {
    payment_log("BŁĄD: Nieprawidłowa kwota '{$kwota}' (klient: {$client_id})");
    header('Location: index.php?page=faktury&error=amount');
    exit;
}

// Walidacja nr faktury - dozwolone: litery, cyfry, /, -, spacja, kropka
if (empty($invoice_nr) || strlen($invoice_nr) > 100 || !preg_match('/^[A-Za-z0-9\/\-\.\s]+$/', $invoice_nr)) {
    payment_log("BŁĄD: Nieprawidłowy nr faktury (klient: {$client_id})");
    header('Location: index.php?page=faktury&error=invoice');
    exit;
}

// Opis płatności
$description = payment_build_description(
    $cfg['description_template'],
    $invoice_nr,
    nr_klienta($client_id)
);

// Utwórz sesję płatności
$token = payment_create_session($gateway, $client_id, $invoice_nr, $amount, $description);
if (!$token) {
    payment_log("BŁĄD: Nie udało się utworzyć sesji płatności (klient: {$client_id})");
    header('Location: index.php?page=faktury&error=init');
    exit;
}

payment_log("Inicjalizacja płatności: {$gateway}, klient: {$client_id}, faktura: {$invoice_nr}, kwota: {$amount}, token: {$token}");

// Bezpieczne wykrywanie bazowego URL (SERVER_NAME jest kontrolowany w konfiguracji Apache)
$server_host = $_SERVER['SERVER_NAME'] ?? $_SERVER['HTTP_HOST'] ?? 'localhost';
// Usuń ewentualny port i niedozwolone znaki
$server_host = preg_replace('/[^a-zA-Z0-9.\-:]/', '', $server_host);
$proto = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$base_url = $proto . '://' . $server_host . dirname($_SERVER['SCRIPT_NAME']);

// URL powrotu
$return_url = $cfg['return_url'];
if (empty($return_url)) {
    $return_url = $base_url . '/payment_return.php';
}
$return_url .= (strpos($return_url, '?') !== false ? '&' : '?') . 'token=' . $token;

// URL powiadomień (IPN)
$notify_url = $cfg['notification_url'];
if (empty($notify_url)) {
    $notify_url = $base_url . '/payment_callback.php?gateway=' . $gateway;
}

// Email klienta (opcjonalny) — z danych klienta (vUserdb)
$client_email = '';
$client_info = vbk_read_infoadmin($client_id);
if (!empty($client_info['email']) && filter_var($client_info['email'], FILTER_VALIDATE_EMAIL)) {
    $client_email = $client_info['email'];
}

// ==========================================
// Przekierowanie do bramki
// ==========================================

switch ($gateway) {
    case 'tpay':
        init_tpay($cfg, $token, $amount, $description, $return_url, $notify_url, $client_email);
        break;
    case 'p24':
        init_p24($cfg, $token, $amount, $description, $return_url, $notify_url, $client_email);
        break;
    case 'payu':
        init_payu($cfg, $token, $amount, $description, $return_url, $notify_url, $client_email);
        break;
}

// ==========================================
// Funkcje inicjalizacji bramek
// ==========================================

/**
 * Tpay - OpenAPI: autoryzacja OAuth2 + utworzenie transakcji + redirect.
 *
 * Dokumentacja: https://openapi.tpay.com  (https://docs-api.tpay.com)
 * 1) POST {base}/oauth/auth (form-urlencoded) -> access_token
 * 2) POST {base}/transactions (JSON, Bearer) -> transactionPaymentUrl
 * 3) redirect klienta na transactionPaymentUrl (panel wyboru metody płatności Tpay)
 *
 * Powiadomienie (IPN) Tpay zwraca nasz token w polu tr_crc (= hiddenDescription),
 * po którym payment_callback.php odnajduje sesję. MD5 IPN weryfikowane kodem
 * bezpieczeństwa (security_code).
 */
function init_tpay($cfg, $token, $amount, $description, $return_url, $notify_url, $email) {
    $client_id = $cfg['client_id'] ?? '';
    $client_secret = $cfg['client_secret'] ?? '';

    $api_base = !empty($cfg['test_mode'])
        ? 'https://openapi.sandbox.tpay.com'
        : 'https://api.tpay.com';

    // 1. OAuth2 - token dostępu
    $ch = curl_init($api_base . '/oauth/auth');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => http_build_query([
            'client_id' => $client_id,
            'client_secret' => $client_secret,
        ]),
        CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
        CURLOPT_TIMEOUT => 30,
    ]);
    $response = curl_exec($ch);
    curl_close($ch);

    $auth = json_decode($response, true);
    if (empty($auth['access_token'])) {
        $error_msg = $auth['error_description'] ?? ($auth['error'] ?? ($response ?: 'OAuth failed'));
        payment_log("BŁĄD Tpay: autoryzacja OAuth nie powiodła się: {$error_msg}, token: {$token}");
        payment_fail_session($token, 'Tpay OAuth failed: ' . $error_msg);
        header('Location: payment_return.php?token=' . $token . '&status=error');
        exit;
    }

    $access_token = $auth['access_token'];

    // 2. Utworzenie transakcji (bez 'pay' -> Tpay pokazuje panel wyboru metody)
    $tx_data = [
        'amount' => round((float)$amount, 2),
        'description' => $description,
        'hiddenDescription' => $token, // wraca w powiadomieniu jako tr_crc
        'lang' => 'pl',
        'payer' => [
            'email' => !empty($email) ? $email : 'klient@example.com',
            'name'  => !empty($email) ? $email : 'Klient',
        ],
        'callbacks' => [
            'notification' => [
                'url' => $notify_url,
            ],
            'payerUrls' => [
                'success' => $return_url,
                'error'   => $return_url . '&status=error',
            ],
        ],
    ];

    $ch = curl_init($api_base . '/transactions');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode($tx_data, JSON_UNESCAPED_UNICODE),
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'Accept: application/json',
            'Authorization: Bearer ' . $access_token,
        ],
        CURLOPT_TIMEOUT => 30,
    ]);
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $result = json_decode($response, true);

    // Sukces: redirect na transactionPaymentUrl (tylko domeny Tpay)
    if (($http_code === 200 || $http_code === 201) && !empty($result['transactionPaymentUrl'])) {
        $pay_url = $result['transactionPaymentUrl'];
        $host = parse_url($pay_url, PHP_URL_HOST) ?: '';
        if (preg_match('/(^|\.)tpay\.com$/', $host)) {
            $tr_id = $result['transactionId'] ?? '?';
            payment_log("Tpay: transakcja utworzona, tr_id: {$tr_id}, redirect: {$host}, token: {$token}");
            header('Location: ' . $pay_url);
            exit;
        }
        payment_log("BŁĄD Tpay: niedozwolona domena redirect: {$host}, token: {$token}");
        payment_fail_session($token, 'Tpay redirect to untrusted domain: ' . $host);
        header('Location: payment_return.php?token=' . $token . '&status=error');
        exit;
    }

    // Błąd tworzenia transakcji
    $error_msg = '';
    if (!empty($result['errors'][0]['errorMessage'])) {
        $error_msg = $result['errors'][0]['errorMessage'];
    } elseif (!empty($result['errors'][0]['errorCode'])) {
        $error_msg = $result['errors'][0]['errorCode'];
    } elseif (!empty($result['message'])) {
        $error_msg = $result['message'];
    } else {
        $error_msg = $response ?: "HTTP {$http_code}";
    }
    payment_log("BŁĄD Tpay: tworzenie transakcji nie powiodło się: {$error_msg}, token: {$token}");
    payment_fail_session($token, 'Tpay transaction failed: ' . $error_msg);
    header('Location: payment_return.php?token=' . $token . '&status=error');
    exit;
}

/**
 * Przelewy24 - rejestracja transakcji przez API, redirect
 */
function init_p24($cfg, $token, $amount, $description, $return_url, $notify_url, $email) {
    $merchant_id = (int)$cfg['merchant_id'];
    $pos_id = !empty($cfg['pos_id']) ? (int)$cfg['pos_id'] : $merchant_id;
    $crc_key = $cfg['crc_key'];
    $api_key = $cfg['api_key'];
    $amount_gr = (int)round($amount * 100); // grosze

    $api_base = $cfg['test_mode']
        ? 'https://sandbox.przelewy24.pl'
        : 'https://secure.przelewy24.pl';

    // P24 REST v1: sign = SHA-384 z JSON-a (NIE string z |), kolejność pól wg dokumentacji.
    // merchantId i amount jako int, reszta jako string.
    $sign = hash('sha384', json_encode([
        'sessionId'  => $token,
        'merchantId' => $merchant_id,
        'amount'     => $amount_gr,
        'currency'   => 'PLN',
        'crc'        => $crc_key,
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    $data = [
        'merchantId' => $merchant_id,
        'posId' => $pos_id,
        'sessionId' => $token,
        'amount' => $amount_gr,
        'currency' => 'PLN',
        'description' => $description,
        'email' => !empty($email) ? $email : 'klient@example.com',
        'country' => 'PL',
        'language' => 'pl',
        'urlReturn' => $return_url,
        'urlStatus' => $notify_url,
        'sign' => $sign,
    ];

    $ch = curl_init($api_base . '/api/v1/transaction/register');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode($data),
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'Authorization: Basic ' . base64_encode($pos_id . ':' . $api_key),
        ],
        CURLOPT_TIMEOUT => 30,
    ]);
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $result = json_decode($response, true);

    if ($http_code === 200 && !empty($result['data']['token'])) {
        $p24_token = $result['data']['token'];
        // Walidacja tokena P24 (alfanumeryczny)
        if (!preg_match('/^[a-zA-Z0-9_-]+$/', $p24_token)) {
            payment_log("BŁĄD P24: nieprawidłowy token P24: {$p24_token}, token: {$token}");
            payment_fail_session($token, 'P24 invalid token format');
            header('Location: payment_return.php?token=' . $token . '&status=error');
            exit;
        }
        payment_log("P24: zarejestrowano transakcję, p24_token: {$p24_token}, token: {$token}");
        header('Location: ' . $api_base . '/trnRequest/' . $p24_token);
        exit;
    }

    // Błąd
    $error_msg = $result['error'] ?? ($response ?: "HTTP {$http_code}");
    payment_log("BŁĄD P24: rejestracja nie powiodła się: {$error_msg}, token: {$token}");
    payment_fail_session($token, 'P24 registration failed: ' . $error_msg);
    header('Location: payment_return.php?token=' . $token . '&status=error');
    exit;
}

/**
 * PayU - OAuth token + utworzenie zamówienia
 */
function init_payu($cfg, $token, $amount, $description, $return_url, $notify_url, $email) {
    $pos_id = $cfg['pos_id'];
    $md5_key = $cfg['md5_key'];
    $client_id = $cfg['client_id'];
    $client_secret = $cfg['client_secret'];
    $amount_gr = (int)round($amount * 100);

    $api_base = $cfg['test_mode']
        ? 'https://secure.snd.payu.com'
        : 'https://secure.payu.com';

    // 1. OAuth token
    $ch = curl_init($api_base . '/pl/standard/user/oauth/authorize');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => http_build_query([
            'grant_type' => 'client_credentials',
            'client_id' => $client_id,
            'client_secret' => $client_secret,
        ]),
        CURLOPT_TIMEOUT => 30,
    ]);
    $response = curl_exec($ch);
    curl_close($ch);

    $auth = json_decode($response, true);
    if (empty($auth['access_token'])) {
        $error_msg = $auth['error_description'] ?? ($response ?: 'OAuth failed');
        payment_log("BŁĄD PayU: OAuth nie powiodło się: {$error_msg}, token: {$token}");
        payment_fail_session($token, 'PayU OAuth failed: ' . $error_msg);
        header('Location: payment_return.php?token=' . $token . '&status=error');
        exit;
    }

    $access_token = $auth['access_token'];

    // 2. Utworzenie zamówienia
    $order_data = [
        'notifyUrl' => $notify_url,
        'continueUrl' => $return_url,
        'customerIp' => $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1',
        'merchantPosId' => $pos_id,
        'description' => $description,
        'currencyCode' => 'PLN',
        'totalAmount' => (string)$amount_gr,
        'extOrderId' => $token,
        'products' => [
            [
                'name' => $description,
                'unitPrice' => (string)$amount_gr,
                'quantity' => '1',
            ],
        ],
    ];

    if (!empty($email)) {
        $order_data['buyer'] = ['email' => $email, 'language' => 'pl'];
    }

    $ch = curl_init($api_base . '/api/v2_1/orders');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode($order_data),
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $access_token,
        ],
        CURLOPT_TIMEOUT => 30,
        CURLOPT_FOLLOWLOCATION => false, // PayU returns 302 with redirect
    ]);
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $redirect_url = curl_getinfo($ch, CURLINFO_REDIRECT_URL);
    curl_close($ch);

    $result = json_decode($response, true);

    // PayU returns 302 redirect or 200 with redirectUri
    // Walidacja: redirect tylko do domen PayU
    $payu_redirect = !empty($redirect_url) ? $redirect_url : ($result['redirectUri'] ?? '');
    if (!empty($payu_redirect)) {
        $parsed = parse_url($payu_redirect);
        $host = $parsed['host'] ?? '';
        // Dozwolone domeny PayU
        if (preg_match('/^(secure\.payu\.com|secure\.snd\.payu\.com|merch-prod\.snd\.payu\.com)$/', $host)
            || preg_match('/\.payu\.com$/', $host)) {
            payment_log("PayU: zamówienie utworzone, redirect do: {$host}, token: {$token}");
            header('Location: ' . $payu_redirect);
            exit;
        }
        payment_log("BŁĄD PayU: niedozwolona domena redirect: {$host}, token: {$token}");
        payment_fail_session($token, 'PayU redirect to untrusted domain: ' . $host);
        header('Location: payment_return.php?token=' . $token . '&status=error');
        exit;
    }

    // Błąd
    $error_msg = '';
    if (!empty($result['status']['statusDesc'])) {
        $error_msg = $result['status']['statusDesc'];
    } elseif (!empty($result['error'])) {
        $error_msg = $result['error'];
    } else {
        $error_msg = $response ?: "HTTP {$http_code}";
    }
    payment_log("BŁĄD PayU: tworzenie zamówienia nie powiodło się: {$error_msg}, token: {$token}");
    payment_fail_session($token, 'PayU order failed: ' . $error_msg);
    header('Location: payment_return.php?token=' . $token . '&status=error');
    exit;
}
