<?php
declare(strict_types=1);

require_once __DIR__ . '/../config/bootstrap.php';

require_permission($conn, 'queue');
process_post_only_or_redirect('../pages/dashboard.php');

$orderId = filter_input(INPUT_POST, 'order_id', FILTER_VALIDATE_INT);
$orderRedirectPath = process_order_redirect_path($orderId);
ensure_post_csrf_or_redirect('queue_payment_save', $orderRedirectPath);

ensure_payment_tender_columns($conn);
ensure_payment_slip_columns($conn);

$receivedRaw = str_replace(',', '', trim((string) ($_POST['received_amount'] ?? ($_POST['amount'] ?? '0'))));
$paymentMethod = trim((string) ($_POST['payment_method'] ?? 'cash'));
$note = trim((string) ($_POST['note'] ?? ''));
$slipFile = $_FILES['slip_file'] ?? null;
$allowedPaymentMethods = array('cash', 'transfer', 'qr', 'card');
$oldInput = array(
    'payment_method' => $paymentMethod,
    'received_amount' => $receivedRaw,
    'note' => $note,
);

if (!$orderId) {
    redirect_with_flash(
        '../pages/dashboard.php',
        'error',
        localized_flash_message('ไม่พบบิลที่ต้องการรับชำระ', 'Invalid payment target.')
    );
}

ensure_submission_token_or_redirect(
    'queue_payment_save_' . $orderId,
    $orderRedirectPath,
    $oldInput
);

process_ensure_permission_or_redirect(
    $conn,
    'queue_payment',
    $orderRedirectPath,
    localized_flash_message('คุณไม่มีสิทธิ์รับชำระเงินงานคิว', 'You do not have permission to receive queue payment.')
);

if (!in_array($paymentMethod, $allowedPaymentMethods, true)) {
    $paymentMethod = 'cash';
    $oldInput['payment_method'] = $paymentMethod;
}

$moneyToCents = static function ($value): int {
    $numericValue = is_numeric($value) ? (float) $value : 0.0;

    return max(0, (int) round($numericValue * 100));
};

$centsToMoney = static function (int $value): float {
    return max(0, $value) / 100;
};

$receivedAmountCents = $moneyToCents($receivedRaw);
if ($receivedAmountCents <= 0) {
    redirect_with_flash(
        $orderRedirectPath,
        'error',
        localized_flash_message('จำนวนเงินที่รับมาต้องมากกว่า 0', 'Received amount must be greater than zero.'),
        $oldInput
    );
}

$hasSlipUpload = is_array($slipFile)
    && (int) ($slipFile['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE;

if ($hasSlipUpload && !payment_method_supports_slip($paymentMethod)) {
    redirect_with_flash(
        $orderRedirectPath,
        'error',
        localized_flash_message('แนบสลิปได้เฉพาะการโอน, QR หรือบัตร', 'Slip upload is available only for Transfer, QR or Card payments.'),
        $oldInput
    );
}

$conn->begin_transaction();
$storedSlip = null;

try {
    $order = process_load_order_context_or_redirect(
        $conn,
        $orderId,
        '../pages/dashboard.php',
        localized_flash_message('ไม่พบบิล', 'Order not found.'),
        array(
            'branch_redirect_path' => '../pages/dashboard.php',
            'branch_message' => localized_flash_message('คุณไม่มีสิทธิ์เข้าถึงสาขานี้', 'Branch access denied.'),
        )
    );

    if ((string) ($order['status'] ?? '') !== 'done') {
        $conn->rollback();
        redirect_with_flash(
            $orderRedirectPath,
            'error',
            localized_flash_message('รับชำระเงินได้หลังงานเสร็จสิ้นแล้วเท่านั้น', 'Payment can be saved after the job is completed.'),
            $oldInput
        );
    }

    $paidBeforeAmount = (float) ($order['paid_amount'] ?? 0);
    $paidBeforeAmountCents = $moneyToCents($paidBeforeAmount);
    $totalPriceCents = $moneyToCents($order['total_price'] ?? 0);
    $balanceBeforePaymentCents = max(0, $totalPriceCents - $paidBeforeAmountCents);
    $balanceBeforePayment = $centsToMoney($balanceBeforePaymentCents);

    if ((string) ($order['payment_status'] ?? '') === 'paid' || $balanceBeforePayment <= 0.0) {
        $conn->rollback();
        redirect_with_flash(
            $orderRedirectPath,
            'error',
            localized_flash_message('บิลนี้ชำระครบแล้ว', 'Payment is already completed.'),
            $oldInput
        );
    }

    if ($paymentMethod !== 'cash' && $receivedAmountCents > $balanceBeforePaymentCents) {
        $conn->rollback();
        redirect_with_flash(
            $orderRedirectPath,
            'error',
            localized_flash_message(
                'จำนวนเงินที่รับมาสูงกว่ายอดค้างชำระ กรุณาปรับให้ตรงก่อนปิดบิล',
                'Received amount is higher than the amount due. Adjust it to match before closing the bill.'
            ),
            $oldInput
        );
    }

    $recognizedPaymentCents = min($receivedAmountCents, $balanceBeforePaymentCents);
    $changeAmountCents = $paymentMethod === 'cash'
        ? max(0, $receivedAmountCents - $balanceBeforePaymentCents)
        : 0;

    $recognizedPayment = $centsToMoney($recognizedPaymentCents);
    $receivedAmount = $centsToMoney($receivedAmountCents);
    $changeAmount = $centsToMoney($changeAmountCents);

    if ($hasSlipUpload) {
        $storedSlip = store_payment_slip_upload(is_array($slipFile) ? $slipFile : null, 'queue-payment');
    }

    $slipFilePath = trim((string) ($storedSlip['file_path'] ?? ''));
    $slipFileName = trim((string) ($storedSlip['file_name'] ?? ''));
    $slipMimeType = trim((string) ($storedSlip['mime_type'] ?? ''));
    $slipUploadedAt = trim((string) ($storedSlip['uploaded_at'] ?? ''));

    $paymentStmt = db_prepare($conn, "
        INSERT INTO payments (
            order_id,
            payment_method,
            amount,
            received_amount,
            change_amount,
            note,
            slip_file_path,
            slip_file_name,
            slip_mime_type,
            slip_uploaded_at
        )
        VALUES (?, ?, ?, ?, ?, ?, NULLIF(?, ''), NULLIF(?, ''), NULLIF(?, ''), NULLIF(?, ''))
    ");
    $paymentStmt->bind_param(
        'isdddsssss',
        $orderId,
        $paymentMethod,
        $recognizedPayment,
        $receivedAmount,
        $changeAmount,
        $note,
        $slipFilePath,
        $slipFileName,
        $slipMimeType,
        $slipUploadedAt
    );
    $paymentStmt->execute();
    $paymentId = (int) $conn->insert_id;
    $paymentStmt->close();

    $paidAmount = order_paid_amount($conn, $orderId);
    $paidAmountCents = $moneyToCents($paidAmount);
    $paymentStatus = order_payment_status_from_amounts((float) ($order['total_price'] ?? 0), $paidAmount);

    $updateOrderStmt = db_prepare($conn, "
        UPDATE orders
        SET payment_status = ?
        WHERE order_id = ?
    ");
    $updateOrderStmt->bind_param('si', $paymentStatus, $orderId);
    $updateOrderStmt->execute();
    $updateOrderStmt->close();

    audit_log($conn, array(
        'module_key' => 'payment',
        'action_key' => 'receive',
        'entity_type' => 'payment',
        'entity_id' => $paymentId,
        'order_id' => $orderId,
        'payment_id' => $paymentId,
        'customer_id' => (int) ($order['customer_id'] ?? 0),
        'car_id' => (int) ($order['car_id'] ?? 0),
        'branch_name' => (string) ($order['branch_name'] ?? ''),
        'bill_number' => (string) ($order['bill_number'] ?? ''),
        'amount' => $recognizedPayment,
        'message' => 'Queue payment received.',
        'before' => array(
            'order_status' => (string) ($order['status'] ?? ''),
            'payment_status' => (string) ($order['payment_status'] ?? ''),
            'paid_amount' => $paidBeforeAmount,
            'balance_amount' => $balanceBeforePayment,
        ),
        'after' => array(
            'order_status' => (string) ($order['status'] ?? ''),
            'payment_status' => $paymentStatus,
            'paid_amount' => $paidAmount,
            'balance_amount' => $centsToMoney(max(0, $totalPriceCents - $paidAmountCents)),
            'payment_method' => $paymentMethod,
            'recognized_amount' => $recognizedPayment,
            'received_amount' => $receivedAmount,
            'change_amount' => $changeAmount,
            'note' => $note,
            'has_slip' => $slipFilePath !== '',
        ),
        'meta' => array(
            'order_source' => 'booking',
            'slip_file_name' => $slipFileName,
        ),
    ));

    $conn->commit();
    $_SESSION['booking_payment_method'] = $paymentMethod;

    if ($paymentStatus === 'paid') {
        redirect_with_flash(
            $orderRedirectPath,
            'success',
            localized_flash_message(
                'บันทึกการชำระเงินเรียบร้อยแล้ว บิลนี้ชำระครบแล้ว',
                'Payment saved. Bill is fully paid.'
            )
        );
    }

    $remainingBalance = $centsToMoney(max(0, $totalPriceCents - $paidAmountCents));
    redirect_with_flash(
        $orderRedirectPath,
        'success',
        localized_flash_message(
            'บันทึกการชำระเงินแล้ว ยังคงเหลือ {remaining_balance} บาท',
            'Payment recorded. Outstanding {remaining_balance} THB remains.',
            array('remaining_balance' => format_money($remainingBalance))
        )
    );
} catch (Throwable $exception) {
    process_handle_exception_and_redirect(
        $conn,
        $exception,
        'save_payment',
        $orderRedirectPath,
        localized_flash_message('บันทึกการชำระเงินไม่สำเร็จ', 'Payment was not saved.'),
        array(
            'order_id' => $orderId,
            'payment_method' => $paymentMethod,
            'received_amount' => $receivedRaw,
            'has_slip_upload' => $hasSlipUpload ? 1 : 0,
        ),
        $oldInput,
        true,
        static function () use ($storedSlip): void {
            if (is_array($storedSlip) && !empty($storedSlip['absolute_path']) && is_string($storedSlip['absolute_path'])) {
                @unlink($storedSlip['absolute_path']);
            }
        }
    );
}
