<?php
declare(strict_types=1);

session_start();
require_once 'config.php';
require_once 'includes/canteen_helpers.php';
require_once 'includes/payment_helpers.php';
$conn = getDBConnection();

ini_set('display_errors', '0');
error_reporting(E_ALL);

if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
    http_response_code(405);
    exit;
}

if (!$conn) {
    http_response_code(500);
    exit;
}

$reference = trim((string) ($_GET['reference'] ?? ''));
if ($reference === '' || !preg_match('/^[a-zA-Z0-9_-]+$/', $reference)) {
    header('Location: payment_checkout.php?error=invalid_reference');
    exit;
}

function fetchOnlinePaymentByReference(mysqli $conn, string $reference): ?array
{
    $stmt = $conn->prepare(
        "SELECT op.*, s.first_name, s.last_name
         FROM online_payments op
         INNER JOIN students s ON s.id = op.student_id
         WHERE op.gateway_reference = ?
         LIMIT 1"
    );
    $stmt->bind_param('s', $reference);
    $stmt->execute();
    $result = $stmt->get_result();
    $row = $result->fetch_assoc();
    $stmt->close();
    return $row ?: null;
}

/**
 * Fan a single Paystack transaction back out into one `payments` row per fee
 * item, split proportionally to each item's own amount (not evenly — see
 * proportionalPaymentShares()), and generate canteen entitlements for any
 * feeding-fee item covered. Online payments never reached
 * canteen_auto_generate_entitlement() before; the webhooks were the one
 * payment path it wasn't wired into, so a feeding fee paid online used to
 * grant zero canteen access. weeks_covered comes from the checkout form now
 * (online_payments.weeks_covered) instead of always defaulting to 1 week
 * regardless of how much was actually paid.
 *
 * @return array<int, string> The fee_type of every item paid, for the SMS.
 */
function insertLegacyOnlinePayments(mysqli $conn, array $payment, string $notes): array
{
    $feeIds = json_decode((string) $payment['fee_structure_ids'], true);
    if (!is_array($feeIds) || $feeIds === []) {
        $feeIds = [null];
    }
    $feeIds = array_map(static fn($id) => $id !== null ? (int) $id : null, $feeIds);

    $details = fetchFeeStructureDetails($conn, $feeIds);
    $weights = array_map(static fn($d) => $d['amount'], $details);
    $shares  = proportionalPaymentShares($feeIds, $weights, (float) $payment['amount']);
    $weeksCovered = max(1, (int) ($payment['weeks_covered'] ?? 1));

    $studentId     = (int) $payment['student_id'];
    $method        = 'online';
    $transactionId = (string) $payment['gateway_reference'];

    $stmt = $conn->prepare(
        "INSERT INTO payments
         (student_id, fee_structure_id, amount_paid, payment_date, payment_method, transaction_id, notes)
         VALUES (?, ?, ?, NOW(), ?, ?, ?)"
    );

    $feeTypesPaid = [];
    foreach ($feeIds as $index => $feeId) {
        $amountPaid = $shares[$index];
        $stmt->bind_param('iidsss', $studentId, $feeId, $amountPaid, $method, $transactionId, $notes);
        $stmt->execute();
        $paymentId = $stmt->insert_id;

        if ($feeId !== null && isset($details[$feeId])) {
            $feeTypesPaid[] = $details[$feeId]['fee_type'];
            if (function_exists('canteen_auto_generate_entitlement')) {
                canteen_auto_generate_entitlement($studentId, $paymentId, $details[$feeId]['fee_type'], $weeksCovered);
            }
        }
    }
    $stmt->close();

    return $feeTypesPaid;
}

$payment = fetchOnlinePaymentByReference($conn, $reference);
if (!$payment) {
    header('Location: payment_checkout.php?error=payment_not_found');
    exit;
}

if ($payment['status'] === 'success') {
    header('Location: payment_receipt.php?id=' . (int) $payment['id']);
    exit;
}

$verifyResponse = verifyPaystackPayment($reference);
$responseJson = json_encode($verifyResponse, JSON_UNESCAPED_UNICODE);
$paystackStatus = $verifyResponse['data']['data']['status'] ?? '';
$paystackAmount = (float) ($verifyResponse['data']['data']['amount'] ?? 0);
$success = !empty($verifyResponse['data']['status']) && $paystackStatus === 'success';
$amountMatches = ($paystackAmount / 100) === (float) $payment['amount'];

if ($success && $amountMatches) {
    $conn->begin_transaction();
    try {
        $paymentId = (int) $payment['id'];
        $stmt = $conn->prepare(
            "UPDATE online_payments
             SET status='success', gateway_status='success', gateway_response=?, completed_at=NOW()
             WHERE id=?"
        );
        $stmt->bind_param('si', $responseJson, $paymentId);
        $stmt->execute();
        $stmt->close();

        $feeTypesPaid = insertLegacyOnlinePayments($conn, $payment, 'Online payment via Paystack');

        // Record coupon usage if a coupon was applied
        if (!empty($payment['coupon_id'])) {
            $couponId = (int) $payment['coupon_id'];
            $cuStmt = $conn->prepare("INSERT IGNORE INTO coupon_usages (coupon_id, student_id, payment_id, discount_amount, used_at) VALUES (?, ?, NULL, ?, NOW())");
            $cuStmt->bind_param('iid', $couponId, $payment['student_id'], $payment['discount_amount']);
            $cuStmt->execute();
            $cuStmt->close();
            $conn->query("UPDATE coupons SET times_used = times_used + 1 WHERE id = {$couponId}");
        }

        $conn->commit();
    } catch (Throwable $e) {
        $conn->rollback();
        error_log('Paystack callback failed: ' . $e->getMessage());
        header('Location: payment_checkout.php?student_id=' . (int) $payment['student_id'] . '&error=payment_failed');
        exit;
    }

    if (!empty($payment['parent_phone'])) {
        $studentName = trim($payment['first_name'] . ' ' . $payment['last_name']);
        $itemsPhrase = $feeTypesPaid !== [] ? ' covering ' . implode(', ', $feeTypesPaid) : '';
        $message = 'EduTrack: Payment of GHS ' . number_format((float) $payment['amount'], 2) . ' received for ' . $studentName . $itemsPhrase . '. Receipt: ' . $payment['receipt_number'] . '. Thank you.';
        sendSMS((string) $payment['parent_phone'], $message);
    }

    header('Location: payment_receipt.php?id=' . (int) $payment['id']);
    exit;
}

$paymentId = (int) $payment['id'];
$gatewayStatus = (string) ($paystackStatus ?: ($verifyResponse['data']['message'] ?? 'failed'));
$stmt = $conn->prepare(
    "UPDATE online_payments
     SET status='failed', gateway_status=?, gateway_response=?
     WHERE id=?"
);
$stmt->bind_param('ssi', $gatewayStatus, $responseJson, $paymentId);
$stmt->execute();
$stmt->close();

header('Location: payment_checkout.php?student_id=' . (int) $payment['student_id'] . '&error=payment_failed');
exit;
