<?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 - IPN Callback (server-to-server)
 *
 * Standalone, BEZ sesji PHP. Routing po ?gateway=.
 * Obsługa: Tpay, Przelewy24, PayU
 */
error_reporting(0);

require_once __DIR__ . '/config.php';
require_once __DIR__ . '/inc/payment.php';
require_once __DIR__ . '/inc/db_config.php';
require_once __DIR__ . '/inc/db_mysql.php';

$gateway = trim($_GET['gateway'] ?? '');

switch ($gateway) {
    case 'tpay':
        handle_tpay();
        break;
    case 'p24':
        handle_p24();
        break;
    case 'payu':
        handle_payu();
        break;
    default:
        payment_log("IPN: nieznana bramka '{$gateway}'");
        http_response_code(400);
        echo 'Unknown gateway';
        exit;
}

// ==========================================
// Tpay IPN
// ==========================================
function handle_tpay() {
    $cfg = payment_load_config('tpay');
    if (!$cfg) {
        payment_log("IPN Tpay: brak konfiguracji");
        http_response_code(400);
        exit;
    }

    // Tpay wysyła POST z danymi transakcji
    $tr_id = $_POST['tr_id'] ?? '';
    $tr_date = $_POST['tr_date'] ?? '';
    $tr_crc = $_POST['tr_crc'] ?? '';       // nasz token
    $tr_amount = $_POST['tr_amount'] ?? '';
    $tr_paid = $_POST['tr_paid'] ?? '';
    $tr_desc = $_POST['tr_desc'] ?? '';
    $tr_status = $_POST['tr_status'] ?? '';
    $tr_error = $_POST['tr_error'] ?? 'none';
    $id = $_POST['id'] ?? '';
    $md5sum = $_POST['md5sum'] ?? '';

    // Weryfikacja MD5: md5(id + tr_id + tr_amount + tr_crc + security_code)
    $expected_md5 = md5($id . $tr_id . $tr_amount . $tr_crc . $cfg['security_code']);

    if (!hash_equals($expected_md5, $md5sum)) {
        payment_log("IPN Tpay: nieprawidłowy MD5, tr_id: {$tr_id}, token: {$tr_crc}");
        echo 'FALSE';
        exit;
    }

    // Wczytaj sesję płatności (z weryfikacją TTL 24h)
    $session = payment_load_session($tr_crc, true);
    if (!$session) {
        payment_log("IPN Tpay: nie znaleziono sesji lub wygasła, token: {$tr_crc}");
        echo 'TRUE'; // Tpay wymaga TRUE
        exit;
    }

    // Weryfikacja kwoty (OBOWIĄZKOWA - odrzuć jeśli kwota nie zgadza się)
    if (abs((float)$tr_amount - $session['amount']) > 0.01) {
        payment_log("IPN Tpay: ODRZUCONO - niezgodność kwoty {$tr_amount} vs {$session['amount']}, token: {$tr_crc}");
        payment_fail_session($tr_crc, "Amount mismatch: {$tr_amount} vs {$session['amount']}");
        echo 'TRUE';
        exit;
    }

    if ($tr_status === 'TRUE' && $tr_error === 'none') {
        payment_complete_session($tr_crc, $tr_id, [
            'tr_date' => $tr_date,
            'tr_paid' => $tr_paid,
        ]);
        db_insert_oplata_ibok($session['client_id'], (float)$tr_amount, $session['description'] ?? '', $tr_date ? substr($tr_date, 0, 10) : null);
        payment_log("IPN Tpay: SUKCES, tr_id: {$tr_id}, kwota: {$tr_amount}, klient: {$session['client_id']}, faktura: {$session['invoice_nr']}");
    } else {
        payment_fail_session($tr_crc, "status: {$tr_status}, error: {$tr_error}");
        payment_log("IPN Tpay: BŁĄD, tr_id: {$tr_id}, status: {$tr_status}, error: {$tr_error}, token: {$tr_crc}");
    }

    echo 'TRUE';
    exit;
}

// ==========================================
// Przelewy24 IPN
// ==========================================
function handle_p24() {
    $cfg = payment_load_config('p24');
    if (!$cfg) {
        payment_log("IPN P24: brak konfiguracji");
        http_response_code(400);
        exit;
    }

    // P24 wysyła POST z JSON
    $input = file_get_contents('php://input');
    $data = json_decode($input, true);
    if (!$data) {
        // Fallback na form-encoded
        $data = $_POST;
    }

    $merchant_id = (int)($data['merchantId'] ?? 0);
    $pos_id = (int)($data['posId'] ?? 0);
    $session_id = $data['sessionId'] ?? '';    // nasz token
    $amount = (int)($data['amount'] ?? 0);
    $origin_amount = (int)($data['originAmount'] ?? 0);
    $currency = $data['currency'] ?? 'PLN';
    $order_id = (int)($data['orderId'] ?? 0);
    $method_id = (int)($data['methodId'] ?? 0);
    $statement = $data['statement'] ?? '';
    $sign = $data['sign'] ?? '';

    $crc_key = $cfg['crc_key'];

    // P24 REST v1: podpis notyfikacji = SHA-384 z JSON-a wszystkich pól notyfikacji + crc,
    // w kolejności wg dokumentacji (NIE string z |). Pola liczbowe jako int.
    $expected_sign = hash('sha384', json_encode([
        'merchantId'   => $merchant_id,
        'posId'        => $pos_id,
        'sessionId'    => $session_id,
        'amount'       => $amount,
        'originAmount' => $origin_amount,
        'currency'     => $currency,
        'orderId'      => $order_id,
        'methodId'     => $method_id,
        'statement'    => $statement,
        'crc'          => $crc_key,
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

    if (!hash_equals($expected_sign, $sign)) {
        payment_log("IPN P24: nieprawidłowy podpis, session: {$session_id}, order: {$order_id}");
        http_response_code(400);
        echo 'Invalid signature';
        exit;
    }

    // Wczytaj sesję (z weryfikacją TTL 24h)
    $session = payment_load_session($session_id, true);
    if (!$session) {
        payment_log("IPN P24: nie znaleziono sesji lub wygasła, token: {$session_id}");
        http_response_code(200);
        exit;
    }

    // Weryfikacja kwoty (grosze vs PLN)
    $expected_amount_gr = (int)round($session['amount'] * 100);
    if ($amount !== $expected_amount_gr) {
        payment_log("IPN P24: ODRZUCONO - niezgodność kwoty {$amount} gr vs {$expected_amount_gr} gr, token: {$session_id}");
        payment_fail_session($session_id, "Amount mismatch: {$amount} vs {$expected_amount_gr} gr");
        http_response_code(200);
        exit;
    }

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

    // P24 REST v1: sign dla /transaction/verify = SHA-384 z JSON {sessionId, orderId, amount, currency, crc}.
    $verify_sign = hash('sha384', json_encode([
        'sessionId' => $session_id,
        'orderId'   => $order_id,
        'amount'    => $amount,
        'currency'  => $currency,
        'crc'       => $crc_key,
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    $verify_data = [
        'merchantId' => (int)$cfg['merchant_id'],
        'posId' => !empty($cfg['pos_id']) ? (int)$cfg['pos_id'] : (int)$cfg['merchant_id'],
        'sessionId' => $session_id,
        'amount' => $amount,
        'currency' => $currency,
        'orderId' => $order_id,
        'sign' => $verify_sign,
    ];

    $ch = curl_init($api_base . '/api/v1/transaction/verify');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_PUT => true,
        CURLOPT_POSTFIELDS => json_encode($verify_data),
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'Authorization: Basic ' . base64_encode($verify_data['posId'] . ':' . $cfg['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 && isset($result['data']['status']) && $result['data']['status'] === 'success') {
        payment_complete_session($session_id, (string)$order_id, [
            'method_id' => $method_id,
            'statement' => $statement,
        ]);
        db_insert_oplata_ibok($session['client_id'], $session['amount'], $session['description'] ?? '');
        payment_log("IPN P24: SUKCES, orderId: {$order_id}, kwota: " . ($amount / 100) . " PLN, klient: {$session['client_id']}, faktura: {$session['invoice_nr']}");
    } else {
        $err = $result['error'] ?? "HTTP {$http_code}";
        payment_fail_session($session_id, "P24 verify failed: {$err}");
        payment_log("IPN P24: weryfikacja negatywna, orderId: {$order_id}, error: {$err}, token: {$session_id}");
    }

    http_response_code(200);
    exit;
}

// ==========================================
// PayU IPN
// ==========================================
function handle_payu() {
    $cfg = payment_load_config('payu');
    if (!$cfg) {
        payment_log("IPN PayU: brak konfiguracji");
        http_response_code(400);
        exit;
    }

    $input = file_get_contents('php://input');

    // Weryfikacja podpisu OpenPayu-Signature (OBOWIĄZKOWA)
    $signature_header = $_SERVER['HTTP_OPENPAYU_SIGNATURE'] ?? '';
    if (empty($signature_header) || empty($cfg['md5_key'])) {
        payment_log("IPN PayU: brak podpisu lub klucza MD5");
        http_response_code(401);
        exit;
    }

    $sig_parts = [];
    foreach (explode(';', $signature_header) as $part) {
        $kv = explode('=', $part, 2);
        if (count($kv) === 2) {
            $sig_parts[trim($kv[0])] = trim($kv[1]);
        }
    }

    $algorithm = $sig_parts['algorithm'] ?? 'MD5';
    $incoming_sig = $sig_parts['signature'] ?? '';

    if (empty($incoming_sig)) {
        payment_log("IPN PayU: pusty podpis w nagłówku");
        http_response_code(401);
        exit;
    }

    if (strtoupper($algorithm) === 'SHA-256' || strtoupper($algorithm) === 'SHA256') {
        $expected_sig = hash('sha256', $input . $cfg['md5_key']);
    } else {
        $expected_sig = md5($input . $cfg['md5_key']);
    }

    if (!hash_equals($expected_sig, $incoming_sig)) {
        payment_log("IPN PayU: nieprawidłowy podpis");
        http_response_code(401);
        exit;
    }

    $data = json_decode($input, true);
    if (!$data || !isset($data['order'])) {
        payment_log("IPN PayU: nieprawidłowy format danych");
        http_response_code(400);
        exit;
    }

    $order = $data['order'];
    $ext_order_id = $order['extOrderId'] ?? '';  // nasz token
    $order_id = $order['orderId'] ?? '';
    $status = $order['status'] ?? '';

    // Wczytaj sesję (z weryfikacją TTL 24h)
    $session = payment_load_session($ext_order_id, true);
    if (!$session) {
        payment_log("IPN PayU: nie znaleziono sesji lub wygasła, extOrderId: {$ext_order_id}");
        http_response_code(200);
        exit;
    }

    if ($status === 'COMPLETED') {
        // Weryfikacja kwoty
        $payu_amount_gr = (int)($order['totalAmount'] ?? 0);
        $expected_amount_gr = (int)round($session['amount'] * 100);
        if ($payu_amount_gr > 0 && $payu_amount_gr !== $expected_amount_gr) {
            payment_log("IPN PayU: ODRZUCONO - niezgodność kwoty {$payu_amount_gr} gr vs {$expected_amount_gr} gr, token: {$ext_order_id}");
            payment_fail_session($ext_order_id, "Amount mismatch: {$payu_amount_gr} vs {$expected_amount_gr} gr");
            http_response_code(200);
            exit;
        }

        payment_complete_session($ext_order_id, $order_id, [
            'payu_status' => $status,
        ]);
        $total = $payu_amount_gr > 0 ? ($payu_amount_gr / 100) : $session['amount'];
        db_insert_oplata_ibok($session['client_id'], $total, $session['description'] ?? '');
        payment_log("IPN PayU: SUKCES, orderId: {$order_id}, kwota: {$total} PLN, klient: {$session['client_id']}, faktura: {$session['invoice_nr']}");
    } elseif ($status === 'CANCELED' || $status === 'REJECTED') {
        payment_fail_session($ext_order_id, "PayU status: {$status}");
        payment_log("IPN PayU: {$status}, orderId: {$order_id}, token: {$ext_order_id}");
    } else {
        // PENDING, WAITING_FOR_CONFIRMATION - ignorujemy, czekamy na COMPLETED
        payment_log("IPN PayU: status {$status}, orderId: {$order_id}, token: {$ext_order_id}");
    }

    http_response_code(200);
    exit;
}
