<?php
declare(strict_types=1);

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

require_login($conn);
require_permission($conn, 'queue');

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

process_post_only_or_redirect('../pages/queue.php');

$paymentId = (int) (filter_input(INPUT_POST, 'payment_id', FILTER_VALIDATE_INT) ?: 0);
$orderId = (int) (filter_input(INPUT_POST, 'order_id', FILTER_VALIDATE_INT) ?: 0);
$scopeRaw = trim((string) ($_POST['deposit_scope'] ?? ''));
$amountRaw = trim((string) ($_POST['deposit_edit_amount'] ?? ''));
$methodRaw = trim((string) ($_POST['deposit_edit_method'] ?? 'cash'));
$depositSlipFile = $_FILES['deposit_slip_file'] ?? null;
$hasSlipUpload = is_array($depositSlipFile)
    && ((int) ($depositSlipFile['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE);

$fallbackReturn = 'job_details.php?id=' . $orderId . '&open_deposit=1#deposit-management';
$returnPath = process_safe_return_path((string) ($_POST['return_to'] ?? ''), '../pages/' . $fallbackReturn);
$preferredLandingPath = '../pages/' . auth_preferred_landing_page($conn);
$paymentMethods = quick_service_payment_methods();

ensure_post_csrf_or_redirect('booking_deposit_manage', $returnPath);

if ($orderId <= 0) {
    redirect_with_flash('../pages/queue.php', 'error', localized_flash_message('ไม่พบบิลจอง', 'Booking was not found.'));
}

if (!array_key_exists($methodRaw, $paymentMethods)) {
    redirect_with_flash($returnPath, 'error', localized_flash_message('วิธีชำระเงินไม่ถูกต้อง', 'Payment method is invalid.'), array(
        'deposit_edit_amount' => $amountRaw,
        'deposit_edit_method' => $methodRaw,
        'edit_deposit_scope' => $scopeRaw,
        'edit_deposit_payment_id' => $paymentId,
    ));
}

if ($amountRaw === '' || !is_numeric($amountRaw)) {
    redirect_with_flash($returnPath, 'error', localized_flash_message('จำนวนเงินมัดจำไม่ถูกต้อง', 'Deposit amount is invalid.'), array(
        'deposit_edit_amount' => $amountRaw,
        'deposit_edit_method' => $methodRaw,
        'edit_deposit_scope' => $scopeRaw,
        'edit_deposit_payment_id' => $paymentId,
    ));
}

$newAmount = round((float) $amountRaw, 2);
if ($newAmount <= 0.0) {
    redirect_with_flash($returnPath, 'error', localized_flash_message('จำนวนเงินมัดจำต้องมากกว่า 0', 'Deposit amount must be greater than zero.'), array(
        'deposit_edit_amount' => $amountRaw,
        'deposit_edit_method' => $methodRaw,
        'edit_deposit_scope' => $scopeRaw,
        'edit_deposit_payment_id' => $paymentId,
    ));
}

if ($hasSlipUpload && !payment_method_supports_slip($methodRaw)) {
    redirect_with_flash($returnPath, 'error', localized_flash_message('แนบสลิปมัดจำได้เฉพาะการโอน, QR หรือบัตร', 'Deposit slip upload is available only for Transfer, QR or Card payments.'), array(
        'deposit_edit_amount' => $amountRaw,
        'deposit_edit_method' => $methodRaw,
        'edit_deposit_scope' => $scopeRaw,
        'edit_deposit_payment_id' => $paymentId,
    ));
}

$orderStmt = db_prepare($conn, "
    SELECT
        order_id,
        bill_number,
        branch_name,
        customer_id,
        car_id,
        total_price,
        deposit_amount,
        deposit_method,
        payment_status,
        admin_deposit_amount,
        admin_deposit_method,
        branch_deposit_amount,
        branch_deposit_method
    FROM orders
    WHERE order_id = ?
    LIMIT 1
");
$orderStmt->bind_param('i', $orderId);
$orderStmt->execute();
$orderRow = $orderStmt->get_result()->fetch_assoc();
$orderStmt->close();

if (!$orderRow) {
    redirect_with_flash('../pages/queue.php', 'error', localized_flash_message('ไม่พบบิลจอง', 'Booking was not found.'));
}

if (!auth_can_access_branch($conn, (string) ($orderRow['branch_name'] ?? ''))) {
    redirect_with_flash($preferredLandingPath, 'error', localized_flash_message('คุณไม่มีสิทธิ์เข้าถึงสาขานี้', 'You do not have access to that branch.'));
}

$paymentRow = null;
if ($paymentId > 0) {
    $paymentStmt = db_prepare($conn, "
        SELECT
            payment_id,
            order_id,
            payment_method,
            amount,
            received_amount,
            change_amount,
            note,
            slip_file_path,
            slip_file_name,
            slip_mime_type,
            slip_uploaded_at
        FROM payments
        WHERE payment_id = ?
            AND order_id = ?
        LIMIT 1
    ");
    $paymentStmt->bind_param('ii', $paymentId, $orderId);
    $paymentStmt->execute();
    $paymentRow = $paymentStmt->get_result()->fetch_assoc();
    $paymentStmt->close();

    if (!$paymentRow) {
        redirect_with_flash('../pages/queue.php', 'error', localized_flash_message('ไม่พบรายการชำระมัดจำ', 'Deposit payment was not found.'));
    }
}

$depositScope = '';
$paymentNote = '';

if ($paymentRow) {
    $paymentNote = trim((string) ($paymentRow['note'] ?? ''));
    if ($paymentNote === 'Admin deposit at booking') {
        $depositScope = 'admin';
    } elseif ($paymentNote === 'Branch deposit at booking') {
        $depositScope = 'branch';
    }

    if ($depositScope === '') {
        redirect_with_flash($returnPath, 'error', localized_flash_message('หน้านี้แก้ไขได้เฉพาะรายการมัดจำจากการจอง', 'Only booking deposit payments can be edited here.'));
    }
} else {
    if (!in_array($scopeRaw, array('admin', 'branch'), true)) {
        redirect_with_flash($returnPath, 'error', localized_flash_message('ยังไม่ได้เลือกประเภทมัดจำ', 'Deposit type was not selected.'), array(
            'deposit_edit_amount' => $amountRaw,
            'deposit_edit_method' => $methodRaw,
            'edit_deposit_scope' => $scopeRaw,
        ));
    }

    $depositScope = $scopeRaw;
    $paymentNote = $depositScope === 'admin' ? 'Admin deposit at booking' : 'Branch deposit at booking';

    $existingDepositStmt = db_prepare($conn, "
        SELECT
            payment_id,
            order_id,
            payment_method,
            amount,
            received_amount,
            change_amount,
            note,
            slip_file_path,
            slip_file_name,
            slip_mime_type,
            slip_uploaded_at
        FROM payments
        WHERE order_id = ?
            AND note = ?
        ORDER BY payment_date DESC, payment_id DESC
        LIMIT 1
    ");
    $existingDepositStmt->bind_param('is', $orderId, $paymentNote);
    $existingDepositStmt->execute();
    $existingDepositRow = $existingDepositStmt->get_result()->fetch_assoc();
    $existingDepositStmt->close();

    if ($existingDepositRow) {
        $paymentRow = $existingDepositRow;
        $paymentId = (int) ($paymentRow['payment_id'] ?? 0);
    }
}

$requiredPermission = $depositScope === 'admin' ? 'booking_deposit_admin_edit' : 'booking_deposit_branch_edit';
process_ensure_permission_or_redirect(
    $conn,
    $requiredPermission,
    $returnPath,
    localized_flash_message('คุณไม่มีสิทธิ์แก้ไขรายการมัดจำนี้', 'You do not have permission to edit that deposit.')
);

$otherPaidStmt = db_prepare($conn, "
    SELECT COALESCE(SUM(amount), 0) AS other_paid_amount
    FROM payments
    WHERE order_id = ?
        AND payment_id <> ?
");
$otherPaidStmt->bind_param('ii', $orderId, $paymentId);
$otherPaidStmt->execute();
$otherPaidAmount = (float) (($otherPaidStmt->get_result()->fetch_assoc()['other_paid_amount'] ?? 0));
$otherPaidStmt->close();

$currentAdminDepositAmount = round((float) ($orderRow['admin_deposit_amount'] ?? 0), 2);
$currentBranchDepositAmount = round((float) ($orderRow['branch_deposit_amount'] ?? 0), 2);
$adminDepositMethod = trim((string) ($orderRow['admin_deposit_method'] ?? ''));
$branchDepositMethod = trim((string) ($orderRow['branch_deposit_method'] ?? ''));
$totalPrice = round((float) ($orderRow['total_price'] ?? 0), 2);
$currentPaymentAmount = round((float) ($paymentRow['amount'] ?? ($depositScope === 'admin' ? $currentAdminDepositAmount : $currentBranchDepositAmount)), 2);
$currentPaymentMethod = trim((string) ($paymentRow['payment_method'] ?? ($depositScope === 'admin' ? $adminDepositMethod : ($branchDepositMethod ?: 'cash'))));
$currentSlipPath = trim((string) ($paymentRow['slip_file_path'] ?? ''));
$currentSlipName = trim((string) ($paymentRow['slip_file_name'] ?? ''));
$currentSlipMimeType = trim((string) ($paymentRow['slip_mime_type'] ?? ''));
$currentSlipUploadedAt = trim((string) ($paymentRow['slip_uploaded_at'] ?? ''));

$updatedAdminDepositAmount = $depositScope === 'admin' ? $newAmount : $currentAdminDepositAmount;
$updatedBranchDepositAmount = $depositScope === 'branch' ? $newAmount : $currentBranchDepositAmount;
$updatedAdminDepositMethod = $depositScope === 'admin' ? $methodRaw : $adminDepositMethod;
$updatedBranchDepositMethod = $depositScope === 'branch' ? $methodRaw : $branchDepositMethod;
$updatedDepositAmount = round($updatedAdminDepositAmount + $updatedBranchDepositAmount, 2);
$updatedPaidAmount = round($otherPaidAmount + $newAmount, 2);

if ($totalPrice > 0.0 && $updatedPaidAmount > $totalPrice + 0.00001) {
    redirect_with_flash($returnPath, 'error', localized_flash_message('ยอดชำระรวมต้องไม่เกินยอดบิล', 'Total paid cannot exceed the bill total.'), array(
        'deposit_edit_amount' => $amountRaw,
        'deposit_edit_method' => $methodRaw,
        'edit_deposit_scope' => $depositScope,
        'edit_deposit_payment_id' => $paymentId,
    ));
}

$updatedDepositMethod = '';
if ($updatedAdminDepositAmount > 0.0 && $updatedBranchDepositAmount > 0.0) {
    if ($updatedAdminDepositMethod !== '' && $updatedBranchDepositMethod !== '' && $updatedAdminDepositMethod !== $updatedBranchDepositMethod) {
        $updatedDepositMethod = 'mixed';
    } else {
        $updatedDepositMethod = $updatedAdminDepositMethod !== '' ? $updatedAdminDepositMethod : $updatedBranchDepositMethod;
    }
} elseif ($updatedAdminDepositAmount > 0.0) {
    $updatedDepositMethod = $updatedAdminDepositMethod;
} elseif ($updatedBranchDepositAmount > 0.0) {
    $updatedDepositMethod = $updatedBranchDepositMethod;
}

$updatedPaymentStatus = order_payment_status_from_amounts($totalPrice, $updatedPaidAmount);

$beforeSnapshot = array(
    'deposit_type' => $depositScope,
    'payment_amount' => $currentPaymentAmount,
    'payment_method' => $currentPaymentMethod,
    'received_amount' => round((float) ($paymentRow['received_amount'] ?? $currentPaymentAmount), 2),
    'deposit_amount' => round((float) ($orderRow['deposit_amount'] ?? 0), 2),
    'admin_deposit_amount' => $currentAdminDepositAmount,
    'admin_deposit_method' => $adminDepositMethod,
    'branch_deposit_amount' => $currentBranchDepositAmount,
    'branch_deposit_method' => $branchDepositMethod,
    'deposit_method' => trim((string) ($orderRow['deposit_method'] ?? '')),
    'payment_status' => (string) ($orderRow['payment_status'] ?? ''),
    'paid_amount' => round($otherPaidAmount + $currentPaymentAmount, 2),
    'has_slip' => $currentSlipPath !== '',
);
$afterSnapshot = array(
    'deposit_type' => $depositScope,
    'payment_amount' => $newAmount,
    'payment_method' => $methodRaw,
    'received_amount' => $newAmount,
    'deposit_amount' => $updatedDepositAmount,
    'admin_deposit_amount' => $updatedAdminDepositAmount,
    'admin_deposit_method' => $updatedAdminDepositMethod,
    'branch_deposit_amount' => $updatedBranchDepositAmount,
    'branch_deposit_method' => $updatedBranchDepositMethod,
    'deposit_method' => $updatedDepositMethod,
    'payment_status' => $updatedPaymentStatus,
    'paid_amount' => $updatedPaidAmount,
);

$storedSlip = null;
$oldSlipToDelete = '';
try {
    if ($hasSlipUpload) {
        $storedSlip = store_payment_slip_upload(is_array($depositSlipFile) ? $depositSlipFile : null, 'booking-' . $depositScope . '-deposit');
    }

    $nextSlipPath = $currentSlipPath;
    $nextSlipName = $currentSlipName;
    $nextSlipMimeType = $currentSlipMimeType;
    $nextSlipUploadedAt = $currentSlipUploadedAt;

    if (!payment_method_supports_slip($methodRaw)) {
        $nextSlipPath = '';
        $nextSlipName = '';
        $nextSlipMimeType = '';
        $nextSlipUploadedAt = '';
        if ($currentSlipPath !== '') {
            $oldSlipToDelete = $currentSlipPath;
        }
    }

    if ($storedSlip) {
        $nextSlipPath = (string) ($storedSlip['file_path'] ?? '');
        $nextSlipName = (string) ($storedSlip['file_name'] ?? '');
        $nextSlipMimeType = (string) ($storedSlip['mime_type'] ?? '');
        $nextSlipUploadedAt = (string) ($storedSlip['uploaded_at'] ?? '');
        if ($currentSlipPath !== '' && $currentSlipPath !== $nextSlipPath) {
            $oldSlipToDelete = $currentSlipPath;
        }
    }

    $afterSnapshot['has_slip'] = $nextSlipPath !== '';

    $conn->begin_transaction();

    if ($paymentId > 0) {
        $updatePaymentStmt = db_prepare($conn, "
            UPDATE payments
            SET
                payment_method = ?,
                amount = ?,
                received_amount = ?,
                change_amount = 0.00,
                slip_file_path = NULLIF(?, ''),
                slip_file_name = NULLIF(?, ''),
                slip_mime_type = NULLIF(?, ''),
                slip_uploaded_at = NULLIF(?, '')
            WHERE payment_id = ?
            LIMIT 1
        ");
        $updatePaymentStmt->bind_param(
            'sddssssi',
            $methodRaw,
            $newAmount,
            $newAmount,
            $nextSlipPath,
            $nextSlipName,
            $nextSlipMimeType,
            $nextSlipUploadedAt,
            $paymentId
        );
        $updatePaymentStmt->execute();
        $updatePaymentStmt->close();
    } else {
        $insertPaymentStmt = db_prepare($conn, "
            INSERT INTO payments (
                order_id,
                payment_method,
                amount,
                received_amount,
                change_amount,
                note,
                payment_date,
                slip_file_path,
                slip_file_name,
                slip_mime_type,
                slip_uploaded_at
            ) VALUES (
                ?,
                ?,
                ?,
                ?,
                0.00,
                ?,
                NOW(),
                NULLIF(?, ''),
                NULLIF(?, ''),
                NULLIF(?, ''),
                NULLIF(?, '')
            )
        ");
        $insertPaymentStmt->bind_param(
            'isddsssss',
            $orderId,
            $methodRaw,
            $newAmount,
            $newAmount,
            $paymentNote,
            $nextSlipPath,
            $nextSlipName,
            $nextSlipMimeType,
            $nextSlipUploadedAt
        );
        $insertPaymentStmt->execute();
        $paymentId = (int) $insertPaymentStmt->insert_id;
        $insertPaymentStmt->close();
    }

    $updateOrderStmt = db_prepare($conn, "
        UPDATE orders
        SET
            admin_deposit_amount = ?,
            admin_deposit_method = ?,
            branch_deposit_amount = ?,
            branch_deposit_method = ?,
            deposit_amount = ?,
            deposit_method = ?,
            payment_status = ?
        WHERE order_id = ?
        LIMIT 1
    ");
    $updateOrderStmt->bind_param(
        'dsdsdssi',
        $updatedAdminDepositAmount,
        $updatedAdminDepositMethod,
        $updatedBranchDepositAmount,
        $updatedBranchDepositMethod,
        $updatedDepositAmount,
        $updatedDepositMethod,
        $updatedPaymentStatus,
        $orderId
    );
    $updateOrderStmt->execute();
    $updateOrderStmt->close();

    audit_log($conn, array(
        'module_key' => 'payment',
        'action_key' => $paymentRow ? 'update' : 'create',
        'entity_type' => 'payment',
        'entity_id' => $paymentId,
        'order_id' => $orderId,
        'payment_id' => $paymentId,
        'customer_id' => (int) ($orderRow['customer_id'] ?? 0),
        'car_id' => (int) ($orderRow['car_id'] ?? 0),
        'branch_name' => (string) ($orderRow['branch_name'] ?? ''),
        'bill_number' => (string) ($orderRow['bill_number'] ?? ''),
        'amount' => $newAmount,
        'message' => ($depositScope === 'admin' ? 'Deposit @Admin' : 'Deposit @Branch') . ($paymentRow ? ' updated.' : ' added.'),
        'before' => $beforeSnapshot,
        'after' => $afterSnapshot,
        'meta' => array(
            'payment_method_before' => $currentPaymentMethod,
            'payment_method_after' => $methodRaw,
            'payment_note' => $paymentNote,
        ),
    ));

    $conn->commit();
} catch (Throwable $exception) {
    process_handle_exception_and_redirect(
        $conn,
        $exception,
        'update_booking_deposit',
        $returnPath,
        localized_flash_message('บันทึกมัดจำไม่สำเร็จ', 'Deposit was not saved.'),
        array(
            'order_id' => $orderId,
            'payment_id' => $paymentId,
            'deposit_scope' => $depositScope !== '' ? $depositScope : $scopeRaw,
            'payment_method' => $methodRaw,
            'has_slip_upload' => $hasSlipUpload ? 1 : 0,
        ),
        array(
            'deposit_edit_amount' => $amountRaw,
            'deposit_edit_method' => $methodRaw,
            'edit_deposit_scope' => $depositScope !== '' ? $depositScope : $scopeRaw,
            'edit_deposit_payment_id' => $paymentId,
        ),
        true,
        static function () use ($storedSlip): void {
            if ($storedSlip) {
                delete_payment_slip_file((string) ($storedSlip['file_path'] ?? ''));
            }
        }
    );
}

if ($oldSlipToDelete !== '') {
    delete_payment_slip_file($oldSlipToDelete);
}

$depositSuccessMessage = $depositScope === 'admin'
    ? localized_flash_message('มัดจำ @Admin บันทึกเรียบร้อยแล้ว', 'Deposit @Admin saved successfully.')
    : localized_flash_message('มัดจำ @Branch บันทึกเรียบร้อยแล้ว', 'Deposit @Branch saved successfully.');

$depositReceiptPath = '../pages/bill_receipt.php?id=' . $orderId
    . '&return_to=' . urlencode('job_details.php?id=' . $orderId);

redirect_with_flash($depositReceiptPath, 'success', $depositSuccessMessage);
