#include <AK/String.h>
#include <AK/Variant.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/Realm.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibWeb/Bindings/DOMMatrixReadOnly.h>
#include <LibWeb/Bindings/DOMPointReadOnly.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/Path2D.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/HTML/Path2D.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Tracing.h>

namespace Web::Bindings {

void Path2DConstructor::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, "Path2D"_utf16), JS::Attribute::Configurable);
    object.define_direct_property(vm.names.prototype, &ensure_web_prototype<Path2DPrototype>(realm, "Path2D"_fly_string), 0);
}

JS::ThrowCompletionOr<GC::Ref<JS::Object>> Path2DConstructor::construct([[maybe_unused]] InterfaceConstructor& constructor, [[maybe_unused]] JS::FunctionObject& new_target)
{
    WebIDL::log_trace(constructor.vm(), "Path2DConstructor::construct");
    auto& vm = constructor.vm();
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // To internally create a new object implementing the interface Path2D:

    // 3.2. Let prototype be ? Get(newTarget, "prototype").
    auto prototype = TRY(new_target.get(vm.names.prototype));

    // 3.3. If Type(prototype) is not Object, then:
    if (!prototype.is_object()) {
        // 1. Let targetRealm be ? GetFunctionRealm(newTarget).
        auto* target_realm = TRY(JS::get_function_realm(vm, new_target));

        // 2. Set prototype to the interface prototype object for interface in targetRealm.
        VERIFY(target_realm);
        prototype = &Bindings::ensure_web_prototype<Path2DPrototype>(*target_realm, "Path2D"_fly_string);
    }

    auto arg0 = vm.argument(0);
    Optional<Variant<GC::Ref<HTML::Path2D>, String>> path {};
    if (!arg0.is_undefined())
        path = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<Variant<GC::Ref<HTML::Path2D>, String>> {

        if (arg0.is_object()) {
            [[maybe_unused]] auto& object = arg0.as_object();

            if (is<PlatformObject>(object)) {

                if (auto* result = as_if<HTML::Path2D>(object))
                    return Variant<GC::Ref<HTML::Path2D>, String> { GC::Ref { *result } };
            }
        }

        auto path_string = TRY([&]() -> JS::ThrowCompletionOr<String> {
        return TRY(WebIDL::to_string(vm, arg0));
    }());
        return Variant<GC::Ref<HTML::Path2D>, String> { path_string };

        return vm.throw_completion<JS::TypeError>("No union types matched"_utf16);
    }(); }));

    auto impl = TRY(throw_dom_exception_if_needed(vm, [&] { return HTML::Path2D::construct_impl(realm, path); }));

    // 7. Set instance.[[Prototype]] to prototype.
    VERIFY(prototype.is_object());
    impl->set_prototype(&prototype.as_object());

    // FIXME: Steps 8...11. of the "internally create a new object implementing the interface Path2D" algorithm
    // (https://webidl.spec.whatwg.org/#js-platform-objects) are currently not handled, or are handled within HTML::Path2D::construct_impl().

    return *impl;
}

void Path2DPrototype::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());
    object.define_native_function(realm, "addPath"_utf16_fly_string, add_path, 1, default_attributes);

    object.define_native_function(realm, "closePath"_utf16_fly_string, close_path, 0, default_attributes);

    object.define_native_function(realm, "moveTo"_utf16_fly_string, move_to, 2, default_attributes);

    object.define_native_function(realm, "lineTo"_utf16_fly_string, line_to, 2, default_attributes);

    object.define_native_function(realm, "quadraticCurveTo"_utf16_fly_string, quadratic_curve_to, 4, default_attributes);

    object.define_native_function(realm, "bezierCurveTo"_utf16_fly_string, bezier_curve_to, 6, default_attributes);

    object.define_native_function(realm, "arcTo"_utf16_fly_string, arc_to, 5, default_attributes);

    object.define_native_function(realm, "rect"_utf16_fly_string, rect, 4, default_attributes);

    object.define_native_function(realm, "roundRect"_utf16_fly_string, round_rect, 4, default_attributes);

    object.define_native_function(realm, "arc"_utf16_fly_string, arc, 5, default_attributes);

    object.define_native_function(realm, "ellipse"_utf16_fly_string, ellipse, 7, default_attributes);

    object.define_direct_property(vm.well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm, "Path2D"_utf16), JS::Attribute::Configurable);
}

void Path2DPrototype::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::Path2D*> impl_from(JS::VM& vm, JS::Value js_value)
{

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

[[maybe_unused]] static JS::ThrowCompletionOr<HTML::Path2D*> 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(Path2DPrototype::add_path)
{
    WebIDL::log_trace(vm, "Path2DPrototype::add_path");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::Path2D* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "addPath");

    auto arg0 = vm.argument(0);
    auto path = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<GC::Ref<HTML::Path2D>> {
        if (auto impl = arg0.as_if<HTML::Path2D>())
            return *impl;
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Path2D");
    }(); }));

    auto arg1 = vm.argument(1);
    DOMMatrix2DInit transform = DOMMatrix2DInit {};
    if (!arg1.is_undefined())
        transform = TRY(throw_dom_exception_if_needed(vm, [&] { return convert_to_idl_value_for_dom_matrix2d_init(vm, arg1); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->add_path(path, transform); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(Path2DPrototype::close_path)
{
    WebIDL::log_trace(vm, "Path2DPrototype::close_path");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::Path2D* idl_object = TRY(impl_from(vm));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->close_path(); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(Path2DPrototype::move_to)
{
    WebIDL::log_trace(vm, "Path2DPrototype::move_to");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::Path2D* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 2)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountMany, "moveTo", "2");

    auto arg0 = vm.argument(0);
    auto x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    auto y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->move_to(x, y); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(Path2DPrototype::line_to)
{
    WebIDL::log_trace(vm, "Path2DPrototype::line_to");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::Path2D* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 2)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountMany, "lineTo", "2");

    auto arg0 = vm.argument(0);
    auto x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    auto y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->line_to(x, y); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(Path2DPrototype::quadratic_curve_to)
{
    WebIDL::log_trace(vm, "Path2DPrototype::quadratic_curve_to");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::Path2D* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 4)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountMany, "quadraticCurveTo", "4");

    auto arg0 = vm.argument(0);
    auto cpx = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    auto cpy = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    auto x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    auto arg3 = vm.argument(3);
    auto y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg3.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->quadratic_curve_to(cpx, cpy, x, y); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(Path2DPrototype::bezier_curve_to)
{
    WebIDL::log_trace(vm, "Path2DPrototype::bezier_curve_to");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::Path2D* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 6)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountMany, "bezierCurveTo", "6");

    auto arg0 = vm.argument(0);
    auto cp1x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    auto cp1y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    auto cp2x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    auto arg3 = vm.argument(3);
    auto cp2y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg3.to_double(vm); }));

    auto arg4 = vm.argument(4);
    auto x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg4.to_double(vm); }));

    auto arg5 = vm.argument(5);
    auto y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg5.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->bezier_curve_to(cp1x, cp1y, cp2x, cp2y, x, y); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(Path2DPrototype::arc_to)
{
    WebIDL::log_trace(vm, "Path2DPrototype::arc_to");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::Path2D* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 5)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountMany, "arcTo", "5");

    auto arg0 = vm.argument(0);
    auto x1 = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    auto y1 = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    auto x2 = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    auto arg3 = vm.argument(3);
    auto y2 = TRY(throw_dom_exception_if_needed(vm, [&] { return arg3.to_double(vm); }));

    auto arg4 = vm.argument(4);
    auto radius = TRY(throw_dom_exception_if_needed(vm, [&] { return arg4.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->arc_to(x1, y1, x2, y2, radius); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(Path2DPrototype::rect)
{
    WebIDL::log_trace(vm, "Path2DPrototype::rect");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::Path2D* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 4)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountMany, "rect", "4");

    auto arg0 = vm.argument(0);
    auto x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    auto y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    auto w = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    auto arg3 = vm.argument(3);
    auto h = TRY(throw_dom_exception_if_needed(vm, [&] { return arg3.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->rect(x, y, w, h); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(Path2DPrototype::round_rect)
{
    WebIDL::log_trace(vm, "Path2DPrototype::round_rect");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::Path2D* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 4)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountMany, "roundRect", "4");

    auto arg0 = vm.argument(0);
    auto x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    auto y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    auto w = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    auto arg3 = vm.argument(3);
    auto h = TRY(throw_dom_exception_if_needed(vm, [&] { return arg3.to_double(vm); }));

    auto arg4 = vm.argument(4);
    Variant<double, DOMPointInit, Vector<Variant<double, DOMPointInit>>> radii = Variant<double, DOMPointInit, Vector<Variant<double, DOMPointInit>>> { 0 };
    if (!arg4.is_undefined())
        radii = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<Variant<double, DOMPointInit, Vector<Variant<double, DOMPointInit>>>> {

        if (arg4.is_nullish()) {
            return Variant<double, DOMPointInit, Vector<Variant<double, DOMPointInit>>> { TRY(convert_to_idl_value_for_dom_point_init(vm, arg4)) };
        }

        if (arg4.is_object()) {
            [[maybe_unused]] auto& object = arg4.as_object();

            // 1. Let method be ? GetMethod(V, @@iterator).
            auto method = TRY(arg4.get_method(vm, vm.well_known_symbol_iterator()));

            // 2. If method is not undefined, return the result of creating a sequence of that type from V and method.
            if (method) {
                auto sequence_union_type = TRY([&]() -> JS::ThrowCompletionOr<Vector<Variant<double, DOMPointInit>>> {
        // To create an IDL value of type sequence<T> given an iterable iterable and an iterator getter method, perform the following steps:
        // 1. Let iteratorRecord be ? GetIteratorFromMethod(iterable, method).
        auto iterator = TRY(JS::get_iterator_from_method(vm, arg4, *method));

        Vector<Variant<double, DOMPointInit>> sequence;

        // 2. Initialize i to be 0.
        // 3. Repeat
        for (;;) {
            // 1. Let next be ? IteratorStepValue(iteratorRecord).
            auto next = TRY(JS::iterator_step_value(vm, iterator));

            // 2. If next is done, then return an IDL sequence value of type sequence<T> of length i, where the value of the element at index j is Sj.
            if (!next.has_value())
                break;

            // 3. Initialize Si to the result of converting next to an IDL value of type T.
            auto next_value = next.release_value();
            auto sequence_item = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<Variant<double, DOMPointInit>> {

        if (next_value.is_nullish()) {
            return Variant<double, DOMPointInit> { TRY(convert_to_idl_value_for_dom_point_init(vm, next_value)) };
        }

        if (next_value.is_object()) {
            [[maybe_unused]] auto& object = next_value.as_object();
            return Variant<double, DOMPointInit> { TRY(convert_to_idl_value_for_dom_point_init(vm, next_value)) };
        }

        if (next_value.is_number()) {
            auto radii_number = TRY(next_value.to_double(vm));
            return Variant<double, DOMPointInit> { radii_number };
        }

        auto radii_number_fallback = TRY(next_value.to_double(vm));
        return Variant<double, DOMPointInit> { radii_number_fallback };

        return vm.throw_completion<JS::TypeError>("No union types matched"_utf16);
    }(); }));

            // 4. Set i to i + 1.
            sequence.append(sequence_item);
        }

        return sequence;
    }());
                return Variant<double, DOMPointInit, Vector<Variant<double, DOMPointInit>>> { sequence_union_type };
            }

            return Variant<double, DOMPointInit, Vector<Variant<double, DOMPointInit>>> { TRY(convert_to_idl_value_for_dom_point_init(vm, arg4)) };
        }

        if (arg4.is_number()) {
            auto radii_number = TRY(arg4.to_double(vm));
            return Variant<double, DOMPointInit, Vector<Variant<double, DOMPointInit>>> { radii_number };
        }

        auto radii_number_fallback = TRY(arg4.to_double(vm));
        return Variant<double, DOMPointInit, Vector<Variant<double, DOMPointInit>>> { radii_number_fallback };

        return vm.throw_completion<JS::TypeError>("No union types matched"_utf16);
    }(); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->round_rect(x, y, w, h, radii); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(Path2DPrototype::arc)
{
    WebIDL::log_trace(vm, "Path2DPrototype::arc");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::Path2D* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 5)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountMany, "arc", "5");

    auto arg0 = vm.argument(0);
    auto x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    auto y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    auto radius = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    auto arg3 = vm.argument(3);
    auto start_angle = TRY(throw_dom_exception_if_needed(vm, [&] { return arg3.to_double(vm); }));

    auto arg4 = vm.argument(4);
    auto end_angle = TRY(throw_dom_exception_if_needed(vm, [&] { return arg4.to_double(vm); }));

    auto arg5 = vm.argument(5);
    bool counterclockwise = false;
    if (!arg5.is_undefined())
        counterclockwise = TRY(throw_dom_exception_if_needed(vm, [&] { return arg5.to_boolean(); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->arc(x, y, radius, start_angle, end_angle, counterclockwise); }));
    return JS::js_undefined();
}

JS_DEFINE_NATIVE_FUNCTION(Path2DPrototype::ellipse)
{
    WebIDL::log_trace(vm, "Path2DPrototype::ellipse");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] HTML::Path2D* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 7)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountMany, "ellipse", "7");

    auto arg0 = vm.argument(0);
    auto x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    auto y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    auto radius_x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    auto arg3 = vm.argument(3);
    auto radius_y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg3.to_double(vm); }));

    auto arg4 = vm.argument(4);
    auto rotation = TRY(throw_dom_exception_if_needed(vm, [&] { return arg4.to_double(vm); }));

    auto arg5 = vm.argument(5);
    auto start_angle = TRY(throw_dom_exception_if_needed(vm, [&] { return arg5.to_double(vm); }));

    auto arg6 = vm.argument(6);
    auto end_angle = TRY(throw_dom_exception_if_needed(vm, [&] { return arg6.to_double(vm); }));

    auto arg7 = vm.argument(7);
    bool counterclockwise = false;
    if (!arg7.is_undefined())
        counterclockwise = TRY(throw_dom_exception_if_needed(vm, [&] { return arg7.to_boolean(); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->ellipse(x, y, radius_x, radius_y, rotation, start_angle, end_angle, counterclockwise); }));
    return JS::js_undefined();
}

} // namespace Web::Bindings
