#pragma once

#include <AK/HashMap.h>
#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/Types.h>
#include <AK/Variant.h>
#include <AK/Vector.h>
#include <LibJS/Forward.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/Value.h>
#include <LibWeb/Bindings/InterfaceObject.h>

namespace Web::Bindings {

struct URLPatternConstructor {
public:
    static void initialize(JS::Realm&, JS::NativeFunction&);
    static JS::ThrowCompletionOr<GC::Ref<JS::Object>> construct(InterfaceConstructor&, JS::FunctionObject&);

private:
    static JS::ThrowCompletionOr<GC::Ref<JS::Object>> construct0(InterfaceConstructor&, JS::FunctionObject&);
    static JS::ThrowCompletionOr<GC::Ref<JS::Object>> construct1(InterfaceConstructor&, JS::FunctionObject&);
};

struct URLPatternPrototype {
public:
    static void initialize(JS::Realm&, JS::Object&);
    static void define_unforgeable_attributes(JS::Realm&, JS::Object&);

private:
    JS_DECLARE_NATIVE_FUNCTION(protocol_getter);
    JS_DECLARE_NATIVE_FUNCTION(username_getter);
    JS_DECLARE_NATIVE_FUNCTION(password_getter);
    JS_DECLARE_NATIVE_FUNCTION(hostname_getter);
    JS_DECLARE_NATIVE_FUNCTION(port_getter);
    JS_DECLARE_NATIVE_FUNCTION(pathname_getter);
    JS_DECLARE_NATIVE_FUNCTION(search_getter);
    JS_DECLARE_NATIVE_FUNCTION(hash_getter);
    JS_DECLARE_NATIVE_FUNCTION(has_reg_exp_groups_getter);
    JS_DECLARE_NATIVE_FUNCTION(test);
    JS_DECLARE_NATIVE_FUNCTION(exec);
};

struct URLPatternInit {
    Optional<String> base_url {};
    Optional<String> hash {};
    Optional<String> hostname {};
    Optional<String> password {};
    Optional<String> pathname {};
    Optional<String> port {};
    Optional<String> protocol {};
    Optional<String> search {};
    Optional<String> username {};
};

JS::ThrowCompletionOr<URLPatternInit> convert_to_idl_value_for_url_pattern_init(JS::VM&, JS::Value);

struct URLPatternOptions {
    bool ignore_case { false };
};

JS::ThrowCompletionOr<URLPatternOptions> convert_to_idl_value_for_url_pattern_options(JS::VM&, JS::Value);

struct URLPatternComponentResult {
    Optional<OrderedHashMap<String, Variant<String, Empty, Empty>>> groups {};
    Optional<String> input {};
};

JS::ThrowCompletionOr<URLPatternComponentResult> convert_to_idl_value_for_url_pattern_component_result(JS::VM&, JS::Value);

struct URLPatternResult {
    Optional<URLPatternComponentResult> hash {};
    Optional<URLPatternComponentResult> hostname {};
    Optional<Vector<Variant<String, URLPatternInit>>> inputs {};
    Optional<URLPatternComponentResult> password {};
    Optional<URLPatternComponentResult> pathname {};
    Optional<URLPatternComponentResult> port {};
    Optional<URLPatternComponentResult> protocol {};
    Optional<URLPatternComponentResult> search {};
    Optional<URLPatternComponentResult> username {};
};

JS::ThrowCompletionOr<URLPatternResult> convert_to_idl_value_for_url_pattern_result(JS::VM&, JS::Value);

} // namespace Web::Bindings
