#include <AK/TypeCasts.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/PrincipalHostDefined.h>
#include <LibWeb/Bindings/WorkerNavigator.h>
#include <LibWeb/HTML/UniversalGlobalScope.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/HTML/WorkerNavigator.h>
#include <LibWeb/MediaCapabilitiesAPI/MediaCapabilities.h>
#include <LibWeb/PermissionsAPI/Permissions.h>
#include <LibWeb/Serial/Serial.h>
#include <LibWeb/ServiceWorker/ServiceWorkerContainer.h>
#include <LibWeb/StorageAPI/StorageManager.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Tracing.h>
#include <LibWeb/WebIDL/Types.h>
#include <LibWeb/WebLocks/LockManager.h>

namespace Web::Bindings {

void WorkerNavigatorConstructor::initialize(JS::Realm& realm, JS::NativeFunction& object)
{
    auto& vm = realm.vm();
    [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable;

    
    object.define_direct_property(vm.names.length, JS::Value(0), JS::Attribute::Configurable);
    object.define_direct_property(vm.names.name, JS::PrimitiveString::create(vm, "WorkerNavigator"_utf16), JS::Attribute::Configurable);
    object.define_direct_property(vm.names.prototype, &ensure_web_prototype<WorkerNavigatorPrototype>(realm, "WorkerNavigator"_fly_string), 0);
}

JS::ThrowCompletionOr<GC::Ref<JS::Object>> WorkerNavigatorConstructor::construct([[maybe_unused]] InterfaceConstructor& constructor, [[maybe_unused]] JS::FunctionObject& new_target)
{
    WebIDL::log_trace(constructor.vm(), "WorkerNavigatorConstructor::construct");
    return constructor.vm().throw_completion<JS::TypeError>(JS::ErrorType::NotAConstructor, "WorkerNavigator");
}

void WorkerNavigatorPrototype::initialize(JS::Realm& realm, JS::Object& object)
{
    [[maybe_unused]] auto& vm = realm.vm();
    [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable | JS::Attribute::Writable;

    object.set_prototype(realm.intrinsics().object_prototype());

    auto media_capabilities_id = "mediaCapabilities"_utf16_fly_string;
    auto native_media_capabilities_getter = JS::NativeFunction::create(realm, media_capabilities_getter, 0, media_capabilities_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_media_capabilities_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto media_capabilities_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(media_capabilities_id, native_media_capabilities_getter, native_media_capabilities_setter, media_capabilities_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto serial_id = "serial"_utf16_fly_string;
    auto native_serial_getter = JS::NativeFunction::create(realm, serial_getter, 0, serial_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_serial_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto serial_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(serial_id, native_serial_getter, native_serial_setter, serial_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    if (HTML::is_secure_context(Bindings::principal_host_defined_environment_settings_object(realm))) {
        auto service_worker_id = "serviceWorker"_utf16_fly_string;
        auto native_service_worker_getter = JS::NativeFunction::create(realm, service_worker_getter, 0, service_worker_id, &realm, "get"sv);
        GC::Ptr<JS::NativeFunction> native_service_worker_setter;
    
        // 4. Let configurable be false if attr is unforgeable and true otherwise.
        auto service_worker_attributes = default_attributes;
    
        // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.
    
        // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
        object.define_direct_accessor(service_worker_id, native_service_worker_getter, native_service_worker_setter, service_worker_attributes);
    
        // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
        }
    if (HTML::UniversalGlobalScopeMixin::expose_experimental_interfaces()) {
        auto permissions_id = "permissions"_utf16_fly_string;
        auto native_permissions_getter = JS::NativeFunction::create(realm, permissions_getter, 0, permissions_id, &realm, "get"sv);
        GC::Ptr<JS::NativeFunction> native_permissions_setter;
    
        // 4. Let configurable be false if attr is unforgeable and true otherwise.
        auto permissions_attributes = default_attributes;
    
        // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.
    
        // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
        object.define_direct_accessor(permissions_id, native_permissions_getter, native_permissions_setter, permissions_attributes);
    
        // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
        }
    auto app_code_name_id = "appCodeName"_utf16_fly_string;
    auto native_app_code_name_getter = JS::NativeFunction::create(realm, app_code_name_getter, 0, app_code_name_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_app_code_name_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto app_code_name_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(app_code_name_id, native_app_code_name_getter, native_app_code_name_setter, app_code_name_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto app_name_id = "appName"_utf16_fly_string;
    auto native_app_name_getter = JS::NativeFunction::create(realm, app_name_getter, 0, app_name_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_app_name_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto app_name_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(app_name_id, native_app_name_getter, native_app_name_setter, app_name_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto app_version_id = "appVersion"_utf16_fly_string;
    auto native_app_version_getter = JS::NativeFunction::create(realm, app_version_getter, 0, app_version_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_app_version_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto app_version_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(app_version_id, native_app_version_getter, native_app_version_setter, app_version_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto platform_id = "platform"_utf16_fly_string;
    auto native_platform_getter = JS::NativeFunction::create(realm, platform_getter, 0, platform_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_platform_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto platform_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(platform_id, native_platform_getter, native_platform_setter, platform_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto product_id = "product"_utf16_fly_string;
    auto native_product_getter = JS::NativeFunction::create(realm, product_getter, 0, product_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_product_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto product_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(product_id, native_product_getter, native_product_setter, product_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    if (is<HTML::Window>(realm.global_object())) {
        auto product_sub_id = "productSub"_utf16_fly_string;
        auto native_product_sub_getter = JS::NativeFunction::create(realm, product_sub_getter, 0, product_sub_id, &realm, "get"sv);
        GC::Ptr<JS::NativeFunction> native_product_sub_setter;
    
        // 4. Let configurable be false if attr is unforgeable and true otherwise.
        auto product_sub_attributes = default_attributes;
    
        // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.
    
        // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
        object.define_direct_accessor(product_sub_id, native_product_sub_getter, native_product_sub_setter, product_sub_attributes);
    
        // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
        }
    auto user_agent_id = "userAgent"_utf16_fly_string;
    auto native_user_agent_getter = JS::NativeFunction::create(realm, user_agent_getter, 0, user_agent_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_user_agent_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto user_agent_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(user_agent_id, native_user_agent_getter, native_user_agent_setter, user_agent_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    if (is<HTML::Window>(realm.global_object())) {
        auto vendor_id = "vendor"_utf16_fly_string;
        auto native_vendor_getter = JS::NativeFunction::create(realm, vendor_getter, 0, vendor_id, &realm, "get"sv);
        GC::Ptr<JS::NativeFunction> native_vendor_setter;
    
        // 4. Let configurable be false if attr is unforgeable and true otherwise.
        auto vendor_attributes = default_attributes;
    
        // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.
    
        // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
        object.define_direct_accessor(vendor_id, native_vendor_getter, native_vendor_setter, vendor_attributes);
    
        // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
        }
    if (is<HTML::Window>(realm.global_object())) {
        auto vendor_sub_id = "vendorSub"_utf16_fly_string;
        auto native_vendor_sub_getter = JS::NativeFunction::create(realm, vendor_sub_getter, 0, vendor_sub_id, &realm, "get"sv);
        GC::Ptr<JS::NativeFunction> native_vendor_sub_setter;
    
        // 4. Let configurable be false if attr is unforgeable and true otherwise.
        auto vendor_sub_attributes = default_attributes;
    
        // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.
    
        // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
        object.define_direct_accessor(vendor_sub_id, native_vendor_sub_getter, native_vendor_sub_setter, vendor_sub_attributes);
    
        // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
        }
    auto language_id = "language"_utf16_fly_string;
    auto native_language_getter = JS::NativeFunction::create(realm, language_getter, 0, language_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_language_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto language_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(language_id, native_language_getter, native_language_setter, language_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto languages_id = "languages"_utf16_fly_string;
    auto native_languages_getter = JS::NativeFunction::create(realm, languages_getter, 0, languages_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_languages_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto languages_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(languages_id, native_languages_getter, native_languages_setter, languages_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto on_line_id = "onLine"_utf16_fly_string;
    auto native_on_line_getter = JS::NativeFunction::create(realm, on_line_getter, 0, on_line_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_on_line_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto on_line_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(on_line_id, native_on_line_getter, native_on_line_setter, on_line_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto hardware_concurrency_id = "hardwareConcurrency"_utf16_fly_string;
    auto native_hardware_concurrency_getter = JS::NativeFunction::create(realm, hardware_concurrency_getter, 0, hardware_concurrency_id, &realm, "get"sv);
    GC::Ptr<JS::NativeFunction> native_hardware_concurrency_setter;

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto hardware_concurrency_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(hardware_concurrency_id, native_hardware_concurrency_getter, native_hardware_concurrency_setter, hardware_concurrency_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    if (HTML::is_secure_context(Bindings::principal_host_defined_environment_settings_object(realm))) {
        auto storage_id = "storage"_utf16_fly_string;
        auto native_storage_getter = JS::NativeFunction::create(realm, storage_getter, 0, storage_id, &realm, "get"sv);
        GC::Ptr<JS::NativeFunction> native_storage_setter;
    
        // 4. Let configurable be false if attr is unforgeable and true otherwise.
        auto storage_attributes = default_attributes;
    
        // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.
    
        // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
        object.define_direct_accessor(storage_id, native_storage_getter, native_storage_setter, storage_attributes);
    
        // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
        }
    if (HTML::is_secure_context(Bindings::principal_host_defined_environment_settings_object(realm))) {
        auto locks_id = "locks"_utf16_fly_string;
        auto native_locks_getter = JS::NativeFunction::create(realm, locks_getter, 0, locks_id, &realm, "get"sv);
        GC::Ptr<JS::NativeFunction> native_locks_setter;
    
        // 4. Let configurable be false if attr is unforgeable and true otherwise.
        auto locks_attributes = default_attributes;
    
        // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.
    
        // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
        object.define_direct_accessor(locks_id, native_locks_getter, native_locks_setter, locks_attributes);
    
        // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
        }
    if (HTML::is_secure_context(Bindings::principal_host_defined_environment_settings_object(realm))) {
        auto device_memory_id = "deviceMemory"_utf16_fly_string;
        auto native_device_memory_getter = JS::NativeFunction::create(realm, device_memory_getter, 0, device_memory_id, &realm, "get"sv);
        GC::Ptr<JS::NativeFunction> native_device_memory_setter;
    
        // 4. Let configurable be false if attr is unforgeable and true otherwise.
        auto device_memory_attributes = default_attributes;
    
        // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.
    
        // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
        object.define_direct_accessor(device_memory_id, native_device_memory_getter, native_device_memory_setter, device_memory_attributes);
    
        // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
        }
    object.define_direct_property(vm.well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm, "WorkerNavigator"_utf16), JS::Attribute::Configurable);
}

void WorkerNavigatorPrototype::define_unforgeable_attributes(JS::Realm& realm, [[maybe_unused]] JS::Object& object)
{
    [[maybe_unused]] auto& vm = realm.vm();
    [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable;
}

[[maybe_unused]] static JS::ThrowCompletionOr<HTML::WorkerNavigator*> impl_from(JS::VM& vm, JS::Value js_value)
{

    if (auto impl = js_value.as_if<HTML::WorkerNavigator>())
        return impl.ptr();
    return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "WorkerNavigator");
}

[[maybe_unused]] static JS::ThrowCompletionOr<HTML::WorkerNavigator*> impl_from(JS::VM& vm)
{
    auto this_value = vm.this_value();
    if (this_value.is_nullish())
        this_value = &vm.current_realm()->global_object();
    return impl_from(vm, this_value);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::media_capabilities_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::media_capabilities_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->media_capabilities(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::serial_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::serial_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->serial(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::service_worker_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::service_worker_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->service_worker(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::permissions_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::permissions_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->permissions(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::app_code_name_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::app_code_name_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->app_code_name(); }));

    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::app_name_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::app_name_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->app_name(); }));

    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::app_version_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::app_version_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->app_version(); }));

    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::platform_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::platform_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->platform(); }));

    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::product_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::product_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->product(); }));

    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::product_sub_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::product_sub_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->product_sub(); }));

    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::user_agent_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::user_agent_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->user_agent(); }));

    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::vendor_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::vendor_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->vendor(); }));

    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::vendor_sub_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::vendor_sub_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->vendor_sub(); }));

    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::language_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::language_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->language(); }));

    return WebIDL::primitive_string_from_string(vm, R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::languages_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::languages_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->languages(); }));

    return [&]() -> JS::Value {
        // An IDL sequence<T> value S is converted to a JavaScript value as follows:
        // 1. Let n be the length of S.
        auto sequence_length = R.size();

        // 2. Let A be a new Array object created as if by the expression [].
        auto sequence_array = MUST(JS::Array::create(realm, sequence_length));

        // 3. Initialize i to be 0.
        // 4. While i < n:
        for (size_t sequence_index = 0; sequence_index < sequence_length; ++sequence_index) {
            // 1. Let V be the value in S at index i.
            auto& sequence_element = R.at(sequence_index);

            // 2. Let E be the result of converting V to a JavaScript value.
            JS::Value js_sequence_element = WebIDL::primitive_string_from_string(vm, sequence_element);

            // 3. Let P be the result of calling ! ToString(i).
            // 4. Perform ! CreateDataPropertyOrThrow(A, P, E).
            MUST(sequence_array->create_data_property(JS::PropertyKey { sequence_index }, js_sequence_element));

            // 5. Set i to i + 1.
        }

        MUST(sequence_array->set_integrity_level(JS::Object::IntegrityLevel::Frozen));

        // 5. Return A.
        return sequence_array;
    }();
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::on_line_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::on_line_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->on_line(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::hardware_concurrency_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::hardware_concurrency_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->hardware_concurrency(); }));

    return JS::Value(static_cast<double>(R));
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::storage_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::storage_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->storage(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::locks_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::locks_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->locks(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(WorkerNavigatorPrototype::device_memory_getter)
{
    WebIDL::log_trace(vm, "WorkerNavigatorPrototype::device_memory_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->device_memory(); }));

    return JS::Value(R);
}

} // namespace Web::Bindings
