<?php
session_start();
ini_set('display_errors', 0);
error_reporting(E_ALL);
ob_start();

require_once '../db.php';
header('Content-Type: application/json');

$staff_id = (int)($_SESSION['staff_id'] ?? 1);

try {
    // 1. Ensure the unified payments ledger exists (Backward compatible fail-safe)
    $conn->query("CREATE TABLE IF NOT EXISTS `patient_payments` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `invoice_no` varchar(50) NOT NULL,
        `patient_no` varchar(50) NOT NULL,
        `amount_paid` decimal(10,2) NOT NULL,
        `payment_method` varchar(50) NOT NULL,
        `transaction_ref` varchar(150) DEFAULT NULL,
        `processed_by` int(11) NOT NULL,
        `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
        PRIMARY KEY (`id`),
        KEY `idx_inv` (`invoice_no`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");

    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        throw new Exception("Invalid request method.");
    }

    $invoice_no = $conn->real_escape_string($_POST['invoice_no'] ?? '');
    $patient_no = $conn->real_escape_string($_POST['patient_no'] ?? '');
    $method = $conn->real_escape_string($_POST['payment_method'] ?? 'Cash');
    $ref = $conn->real_escape_string($_POST['transaction_ref'] ?? '');
    $amount_tendered = (float)($_POST['amount_paid'] ?? 0);

    if (empty($invoice_no) || $amount_tendered <= 0) {
        throw new Exception("Invalid billing parameters provided.");
    }

    $conn->begin_transaction();

    // 2. Fetch current invoice state safely with locking
    $stmtInv = $conn->prepare("SELECT balance_due FROM patient_invoices WHERE invoice_no = ? FOR UPDATE");
    $stmtInv->bind_param("s", $invoice_no);
    $stmtInv->execute();
    $resInv = $stmtInv->get_result();
    $invoice = $resInv->fetch_assoc();
    $stmtInv->close();

    if (!$invoice) {
        throw new Exception("Target invoice not found in the database.");
    }

    $balance = (float)$invoice['balance_due'];

    if ($balance <= 0) {
        throw new Exception("This invoice is already fully paid.");
    }

    // 3. Handle Cash over-payments (Change given)
    $actual_payment_applied = $amount_tendered;
    if ($amount_tendered > $balance) {
        if ($method !== 'Cash') {
            throw new Exception("Digital payments cannot exceed the outstanding balance.");
        }
        $actual_payment_applied = $balance; // Only record what is owed, the rest is change
    }

    // 4. Log the transaction into the ledger
    $stmtPay = $conn->prepare("INSERT INTO patient_payments (invoice_no, patient_no, amount_paid, payment_method, transaction_ref, processed_by) VALUES (?, ?, ?, ?, ?, ?)");
    $stmtPay->bind_param("ssdssi", $invoice_no, $patient_no, $actual_payment_applied, $method, $ref, $staff_id);
    if (!$stmtPay->execute()) {
        throw new Exception("Failed to record payment ledger: " . $stmtPay->error);
    }
    $stmtPay->close();

    // 5. Update the Invoice Balance and Status
    $new_balance = $balance - $actual_payment_applied;
    $new_status = ($new_balance <= 0) ? 'Paid' : 'Partial';

    $stmtUpd = $conn->prepare("UPDATE patient_invoices SET balance_due = ?, status = ? WHERE invoice_no = ?");
    $stmtUpd->bind_param("dss", $new_balance, $new_status, $invoice_no);
    if (!$stmtUpd->execute()) {
        throw new Exception("Failed to update invoice balance: " . $stmtUpd->error);
    }
    $stmtUpd->close();

    $conn->commit();

    ob_end_clean();
    echo json_encode(['status' => 'success', 'message' => 'Payment processed successfully.', 'balance_remaining' => $new_balance]);
    exit;

} catch (Exception $e) {
    if (isset($conn) && $conn->ping()) {
        $conn->rollback();
    }
    ob_end_clean();
    echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
    exit;
}
?>