<?php
declare(strict_types=1);

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

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

ensure_order_detail_options_column($conn);

$orderId = filter_input(INPUT_POST, 'order_id', FILTER_VALIDATE_INT);
$orderRedirectPath = process_order_redirect_path($orderId);
ensure_post_csrf_or_redirect('job_services_update', $orderRedirectPath);
ensure_order_detail_item_note_column($conn);

$serviceIds = array_values(array_unique(array_filter(array_map('intval', (array) ($_POST['service_ids'] ?? array())))));
$serviceNotesInput = array();
foreach ((array) ($_POST['service_notes'] ?? array()) as $serviceId => $serviceNote) {
    $serviceId = (int) $serviceId;
    $serviceNote = trim((string) $serviceNote);

    if ($serviceId > 0 && $serviceNote !== '') {
        $serviceNotesInput[$serviceId] = $serviceNote;
    }
}
$serviceGroupChoiceInput = array();
foreach ((array) ($_POST['service_group_choice'] ?? array()) as $mainServiceId => $groupId) {
    $mainServiceId = (int) $mainServiceId;
    $groupId = (int) $groupId;

    if ($mainServiceId > 0 && $groupId > 0) {
        $serviceGroupChoiceInput[$mainServiceId] = $groupId;
    }
}
$totalRaw = str_replace(',', '', trim((string) ($_POST['total_price'] ?? '')));
$filmFrontServiceId = (int) ($_POST['film_front_service_id'] ?? 0);
$filmSunroofServiceId = (int) ($_POST['film_sunroof_service_id'] ?? 0);
$filmFrontSideServiceId = (int) ($_POST['film_front_side_service_id'] ?? 0);
$filmRearSideServiceId = (int) ($_POST['film_rear_side_service_id'] ?? 0);
$filmRearServiceId = (int) ($_POST['film_rear_service_id'] ?? 0);
$filmNotes = trim((string) ($_POST['film_notes'] ?? ''));
$packageUsageInput = array();
foreach ((array) ($_POST['package_usage'] ?? array()) as $serviceId => $customerPackageItemId) {
    $serviceId = (int) $serviceId;
    $customerPackageItemId = (int) $customerPackageItemId;

    if ($serviceId > 0 && $customerPackageItemId > 0) {
        $packageUsageInput[$serviceId] = $customerPackageItemId;
    }
}

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

if (empty($serviceIds)) {
    redirect_with_flash(
        $orderRedirectPath,
        'error',
        localized_flash_message('กรุณาเลือกรายการบริการอย่างน้อย 1 รายการ', 'Select at least one service item.')
    );
}

$order = process_load_order_context_or_redirect(
    $conn,
    $orderId,
    '../pages/dashboard.php',
    localized_flash_message('ไม่พบบิลงาน', 'Job was not found.'),
    array(
        'branch_redirect_path' => '../pages/dashboard.php',
        'branch_message' => localized_flash_message('คุณไม่มีสิทธิ์เข้าถึงสาขานี้', 'You do not have access to this branch.'),
    )
);

process_ensure_permission_or_redirect(
    $conn,
    'queue_edit_open',
    $orderRedirectPath,
    localized_flash_message('คุณไม่มีสิทธิ์แก้ไขข้อมูลงานคิว', 'You do not have permission to edit queue data.')
);

process_ensure_order_editable_or_redirect(
    $order,
    $orderRedirectPath,
    localized_flash_message('ข้อมูลบิลถูกล็อกแล้ว', 'Bill data is locked.')
);

$services = service_catalog_rows($conn, array(
    'service_ids' => $serviceIds,
    'active_only' => true,
    'include_inactive_ids' => $serviceIds,
));

if (count($services) !== count($serviceIds)) {
    redirect_with_flash(
        $orderRedirectPath,
        'error',
        localized_flash_message('มีบริการที่เลือกอย่างน้อย 1 รายการไม่พร้อมใช้งาน', 'One or more selected services are not available.')
    );
}

$servicesById = array();
foreach ($services as $service) {
    $serviceIdsKey = (int) ($service['service_id'] ?? 0);
    $servicesById[$serviceIdsKey] = $service;
}
$newServiceNames = array_values(array_map(static function (array $service): string {
    return (string) ($service['service_name'] ?? '');
}, $services));

$filmZoneSelectionsInput = array(
    'front' => $filmFrontServiceId,
    'sunroof' => $filmSunroofServiceId,
    'front_side' => $filmFrontSideServiceId,
    'rear_side' => $filmRearSideServiceId,
    'rear' => $filmRearServiceId,
);

$selectedWindowFilmGroup = null;
foreach ($serviceGroupChoiceInput as $mainServiceId => $groupId) {
    $groupRow = service_group_row($conn, $groupId);
    if (!$groupRow || (int) ($groupRow['show_window_film_details'] ?? 0) !== 1) {
        continue;
    }

    $mainServiceSelected = isset($servicesById[$mainServiceId]);
    if (!$mainServiceSelected) {
        foreach ($services as $service) {
            if ((int) ($service['main_service_id'] ?? 0) === $mainServiceId) {
                $mainServiceSelected = true;
                break;
            }
        }
    }

    if ($mainServiceSelected) {
        $selectedWindowFilmGroup = $groupRow;
        break;
    }
}

$validatedFilmZoneSelections = array();
$windowFilmPayloadServiceId = 0;

if ($selectedWindowFilmGroup) {
    $groupId = (int) ($selectedWindowFilmGroup['group_id'] ?? 0);
    $mainServiceId = (int) ($selectedWindowFilmGroup['main_service_id'] ?? 0);
    $filmServiceIds = array_values(array_unique(array_filter(array_map('intval', array_values($filmZoneSelectionsInput)))));
    $filmServiceRows = array();

    if (!empty($filmServiceIds)) {
        foreach (service_catalog_rows($conn, array(
            'service_ids' => $filmServiceIds,
            'active_only' => true,
            'include_inactive_ids' => $filmServiceIds,
        )) as $filmServiceRow) {
            $filmServiceRows[(int) ($filmServiceRow['service_id'] ?? 0)] = $filmServiceRow;
        }
    }

    foreach ($filmZoneSelectionsInput as $zoneKey => $serviceId) {
        if ($serviceId <= 0) {
            continue;
        }

        $serviceRow = $filmServiceRows[$serviceId] ?? null;
        if (
            !$serviceRow
            || (string) ($serviceRow['service_type'] ?? '') !== 'sub_service'
            || (int) ($serviceRow['group_id'] ?? 0) !== $groupId
        ) {
            redirect_with_flash(
                $orderRedirectPath,
                'error',
                localized_flash_message('รายละเอียดฟิล์มกรองแสงที่เลือกไม่ถูกต้อง', 'Window film detail selection is invalid.')
            );
        }

        $validatedFilmZoneSelections[$zoneKey] = array(
            'service_id' => $serviceId,
            'service_name' => (string) ($serviceRow['service_name'] ?? ''),
        );
    }

    if (empty($validatedFilmZoneSelections)) {
        redirect_with_flash(
            $orderRedirectPath,
            'error',
            localized_flash_message('กรุณาเลือกตัวเลือกฟิล์มกรองแสงอย่างน้อย 1 รายการ', 'Choose at least one window film option.')
        );
    }

    if (isset($servicesById[$mainServiceId])) {
        $windowFilmPayloadServiceId = $mainServiceId;
    } else {
        foreach ($services as $service) {
            if ((int) ($service['main_service_id'] ?? 0) === $mainServiceId || (int) ($service['group_id'] ?? 0) === $groupId) {
                $windowFilmPayloadServiceId = (int) ($service['service_id'] ?? 0);
                break;
            }
        }
    }
}

$conn->begin_transaction();

try {
    $existingDetailStmt = db_prepare($conn, "
        SELECT service_name_snapshot, price, service_options
        FROM order_details
        WHERE order_id = ?
        ORDER BY detail_id ASC
    ");
    $existingDetailStmt->bind_param('i', $orderId);
    $existingDetailStmt->execute();
    $existingDetailResult = $existingDetailStmt->get_result();
    $beforeServiceNames = array();
    while ($detailRow = $existingDetailResult->fetch_assoc()) {
        $beforeServiceNames[] = (string) ($detailRow['service_name_snapshot'] ?? '');
    }
    $existingDetailStmt->close();

    service_release_order_package_effects($conn, $orderId);

    $validatedPackageUsages = array();
    $customerId = (int) ($order['customer_id'] ?? 0);
    $carId = (int) ($order['car_id'] ?? 0);

    foreach ($packageUsageInput as $serviceId => $customerPackageItemId) {
        if (!isset($servicesById[$serviceId])) {
            throw new RuntimeException(localized_flash_message_string(
                'ข้อมูลการใช้แพ็กเกจมีบริการไม่ถูกต้อง',
                'Package usage contains an invalid service.'
            ));
        }

        $service = $servicesById[$serviceId];
        if ((string) ($service['service_type'] ?? 'sub_service') !== 'sub_service') {
            throw new RuntimeException(localized_flash_message_string(
                'ใช้สิทธิ์แพ็กเกจได้เฉพาะบริการย่อยเท่านั้น',
                'Package usage can only be applied to sub services.'
            ));
        }

        $balanceRow = service_customer_package_balance_row($conn, $customerId, $customerPackageItemId, $carId);
        if (!$balanceRow || (int) ($balanceRow['sub_service_id'] ?? 0) !== $serviceId) {
            throw new RuntimeException(localized_flash_message_string(
                'แพ็กเกจที่เลือกไม่สามารถใช้กับบริการย่อยนี้ได้',
                'Selected package balance is not available for this sub service.'
            ));
        }

        $validatedPackageUsages[$serviceId] = $balanceRow;
    }

    $serviceTotal = 0.0;
    $packageDiscount = 0.0;
    foreach ($services as $service) {
        $price = (float) ($service['price'] ?? 0);
        $serviceTotal += $price;

        if (isset($validatedPackageUsages[(int) ($service['service_id'] ?? 0)])) {
            $packageDiscount += $price;
        }
    }

    $payableTotal = max(0.0, $serviceTotal - $packageDiscount);
    if ($totalRaw === '') {
        $totalPrice = $payableTotal;
    } elseif (is_numeric($totalRaw)) {
        $totalPrice = max(0.0, (float) $totalRaw);
    } else {
        throw new RuntimeException(localized_flash_message_string(
            'ยอดรวมราคาไม่ถูกต้อง',
            'Total price is invalid.'
        ));
    }

    $deleteStmt = db_prepare($conn, "
        DELETE FROM order_details
        WHERE order_id = ?
    ");
    $deleteStmt->bind_param('i', $orderId);
    $deleteStmt->execute();
    $deleteStmt->close();

    $packageUsagePayloads = array();
    foreach ($validatedPackageUsages as $serviceId => $balanceRow) {
        $packageUsagePayloads[$serviceId] = service_apply_package_usage($conn, $orderId, $servicesById[$serviceId], $balanceRow);
    }

    $packagePurchasePayloads = array();
    foreach ($services as $service) {
        if ((string) ($service['service_type'] ?? 'sub_service') !== 'package') {
            continue;
        }

        $serviceId = (int) ($service['service_id'] ?? 0);
        $packagePurchasePayloads[$serviceId] = array(
            'items' => service_package_purchase_snapshot($conn, $serviceId),
        );
        service_create_customer_package_purchase($conn, $customerId, $carId, $orderId, $service);
    }

    $insertStmt = db_prepare($conn, "
        INSERT INTO order_details (order_id, service_id, service_name_snapshot, price, duration_minutes, service_options, item_note)
        VALUES (?, ?, ?, ?, ?, ?, NULLIF(?, ''))
    ");

    $windowFilmPayload = null;
    if ($selectedWindowFilmGroup && !empty($validatedFilmZoneSelections)) {
        $windowFilmPayload = array(
            'type' => 'window_tint',
            'group_id' => (int) ($selectedWindowFilmGroup['group_id'] ?? 0),
            'group_name' => (string) ($selectedWindowFilmGroup['group_name'] ?? ''),
            'main_service_id' => (int) ($selectedWindowFilmGroup['main_service_id'] ?? 0),
            'front_service_id' => (int) ($validatedFilmZoneSelections['front']['service_id'] ?? 0),
            'front_service_name' => (string) ($validatedFilmZoneSelections['front']['service_name'] ?? ''),
            'sunroof_service_id' => (int) ($validatedFilmZoneSelections['sunroof']['service_id'] ?? 0),
            'sunroof_service_name' => (string) ($validatedFilmZoneSelections['sunroof']['service_name'] ?? ''),
            'front_side_service_id' => (int) ($validatedFilmZoneSelections['front_side']['service_id'] ?? 0),
            'front_side_service_name' => (string) ($validatedFilmZoneSelections['front_side']['service_name'] ?? ''),
            'rear_side_service_id' => (int) ($validatedFilmZoneSelections['rear_side']['service_id'] ?? 0),
            'rear_side_service_name' => (string) ($validatedFilmZoneSelections['rear_side']['service_name'] ?? ''),
            'rear_service_id' => (int) ($validatedFilmZoneSelections['rear']['service_id'] ?? 0),
            'rear_service_name' => (string) ($validatedFilmZoneSelections['rear']['service_name'] ?? ''),
            'notes' => $filmNotes,
        );
    }

    foreach ($services as $service) {
        $serviceId = (int) ($service['service_id'] ?? 0);
        $serviceName = (string) ($service['service_name'] ?? '');
        $price = (float) ($service['price'] ?? 0);
        $detailPrice = isset($packageUsagePayloads[$serviceId]) ? 0.0 : $price;
        $durationMinutes = 0;
        $serviceOptionsPayload = array();

        if ($windowFilmPayload !== null && $serviceId === $windowFilmPayloadServiceId) {
            $serviceOptionsPayload = array_merge($serviceOptionsPayload, $windowFilmPayload);
        }

        if (isset($packageUsagePayloads[$serviceId])) {
            $serviceOptionsPayload['package_usage'] = $packageUsagePayloads[$serviceId];
        }

        if (isset($packagePurchasePayloads[$serviceId])) {
            $serviceOptionsPayload['package_purchase'] = $packagePurchasePayloads[$serviceId];
        }

        $serviceOptions = empty($serviceOptionsPayload)
            ? null
            : json_encode($serviceOptionsPayload, JSON_UNESCAPED_UNICODE);
        $itemNote = trim((string) ($serviceNotesInput[$serviceId] ?? ''));

        $insertStmt->bind_param('iisdiss', $orderId, $serviceId, $serviceName, $detailPrice, $durationMinutes, $serviceOptions, $itemNote);
        $insertStmt->execute();
    }

    $insertStmt->close();

    $paidAmount = order_paid_amount($conn, $orderId);
    $paymentStatus = order_payment_status_from_amounts($totalPrice, $paidAmount);

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

    $serviceChangeDiff = audit_diff_assoc(
        array(
            'service_names' => $beforeServiceNames,
            'total_price' => (float) ($order['total_price'] ?? 0),
            'payment_status' => (string) ($order['payment_status'] ?? ''),
        ),
        array(
            'service_names' => $newServiceNames,
            'total_price' => $totalPrice,
            'payment_status' => $paymentStatus,
        )
    );

    if (!empty($serviceChangeDiff['after'])) {
        audit_log($conn, array(
            'module_key' => 'queue',
            'action_key' => 'update',
            'entity_type' => 'order_services',
            'entity_id' => $orderId,
            'order_id' => $orderId,
            'customer_id' => $customerId,
            'car_id' => $carId,
            'branch_name' => (string) ($order['branch_name'] ?? ''),
            'bill_number' => (string) ($order['bill_number'] ?? ''),
            'amount' => $totalPrice,
            'message' => 'Job services updated.',
            'before' => $serviceChangeDiff['before'],
            'after' => $serviceChangeDiff['after'],
            'meta' => array(
                'package_usage_count' => count($packageUsagePayloads),
                'package_purchase_count' => count($packagePurchasePayloads),
            ),
        ));
    }

    $conn->commit();

    redirect_with_flash(
        $orderRedirectPath,
        'success',
        localized_flash_message('อัปเดตรายการบริการเรียบร้อยแล้ว', 'Services updated.')
    );
} catch (Throwable $exception) {
    process_handle_exception_and_redirect(
        $conn,
        $exception,
        'update_job_services',
        $orderRedirectPath,
        localized_flash_message('บันทึกรายการบริการไม่สำเร็จ', 'Services were not saved.'),
        array(
            'order_id' => $orderId,
            'service_ids' => $serviceIds,
            'package_usage_count' => count($packageUsageInput),
        )
    );
}
