#pragma once

#include <AK/HashMap.h>
#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/Types.h>
#include <AK/Utf16String.h>
#include <AK/Variant.h>
#include <AK/Vector.h>
#include <LibGC/Ptr.h>
#include <LibJS/Forward.h>
#include <LibJS/Runtime/ArrayBuffer.h>
#include <LibJS/Runtime/DataView.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/Value.h>
#include <LibWeb/Bindings/InterfaceObject.h>
#include <LibWeb/Forward.h>

namespace Web::Bindings {

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

private:
};

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

private:
    JS_DECLARE_NATIVE_FUNCTION(method_getter);
    JS_DECLARE_NATIVE_FUNCTION(url_getter);
    JS_DECLARE_NATIVE_FUNCTION(headers_getter);
    JS_DECLARE_NATIVE_FUNCTION(destination_getter);
    JS_DECLARE_NATIVE_FUNCTION(referrer_getter);
    JS_DECLARE_NATIVE_FUNCTION(referrer_policy_getter);
    JS_DECLARE_NATIVE_FUNCTION(mode_getter);
    JS_DECLARE_NATIVE_FUNCTION(credentials_getter);
    JS_DECLARE_NATIVE_FUNCTION(cache_getter);
    JS_DECLARE_NATIVE_FUNCTION(redirect_getter);
    JS_DECLARE_NATIVE_FUNCTION(integrity_getter);
    JS_DECLARE_NATIVE_FUNCTION(keepalive_getter);
    JS_DECLARE_NATIVE_FUNCTION(is_reload_navigation_getter);
    JS_DECLARE_NATIVE_FUNCTION(is_history_navigation_getter);
    JS_DECLARE_NATIVE_FUNCTION(signal_getter);
    JS_DECLARE_NATIVE_FUNCTION(duplex_getter);
    JS_DECLARE_NATIVE_FUNCTION(body_getter);
    JS_DECLARE_NATIVE_FUNCTION(body_used_getter);
    JS_DECLARE_NATIVE_FUNCTION(clone);
    JS_DECLARE_NATIVE_FUNCTION(array_buffer);
    JS_DECLARE_NATIVE_FUNCTION(blob);
    JS_DECLARE_NATIVE_FUNCTION(bytes);
    JS_DECLARE_NATIVE_FUNCTION(form_data);
    JS_DECLARE_NATIVE_FUNCTION(json);
    JS_DECLARE_NATIVE_FUNCTION(text);
};

enum class RequestDestination : u8 {
    Empty,
    Audio,
    Audioworklet,
    Document,
    Embed,
    Font,
    Frame,
    Iframe,
    Image,
    Json,
    Manifest,
    Object,
    Paintworklet,
    Report,
    Script,
    Sharedworker,
    Style,
    Track,
    Video,
    Worker,
    Xslt,
};

JS::ThrowCompletionOr<RequestDestination> convert_to_idl_value_for_request_destination(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(RequestDestination);

enum class RequestMode : u8 {
    Navigate,
    SameOrigin,
    NoCors,
    Cors,
};

JS::ThrowCompletionOr<RequestMode> convert_to_idl_value_for_request_mode(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(RequestMode);

enum class RequestCredentials : u8 {
    Omit,
    SameOrigin,
    Include,
};

JS::ThrowCompletionOr<RequestCredentials> convert_to_idl_value_for_request_credentials(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(RequestCredentials);

enum class RequestCache : u8 {
    Default,
    NoStore,
    Reload,
    NoCache,
    ForceCache,
    OnlyIfCached,
};

JS::ThrowCompletionOr<RequestCache> convert_to_idl_value_for_request_cache(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(RequestCache);

enum class RequestRedirect : u8 {
    Follow,
    Error,
    Manual,
};

JS::ThrowCompletionOr<RequestRedirect> convert_to_idl_value_for_request_redirect(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(RequestRedirect);

enum class RequestDuplex : u8 {
    Half,
};

JS::ThrowCompletionOr<RequestDuplex> convert_to_idl_value_for_request_duplex(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(RequestDuplex);

enum class RequestPriority : u8 {
    High,
    Low,
    Auto,
};

JS::ThrowCompletionOr<RequestPriority> convert_to_idl_value_for_request_priority(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(RequestPriority);

enum class ReferrerPolicy : u8 {
    Empty,
    NoReferrer,
    NoReferrerWhenDowngrade,
    SameOrigin,
    Origin,
    StrictOrigin,
    OriginWhenCrossOrigin,
    StrictOriginWhenCrossOrigin,
    UnsafeUrl,
};

JS::ThrowCompletionOr<ReferrerPolicy> convert_to_idl_value_for_referrer_policy(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(ReferrerPolicy);

struct RequestInit {
    Optional<Variant<GC::Ref<Streams::ReadableStream>, GC::Ref<FileAPI::Blob>, GC::Ref<JS::Int8Array>, GC::Ref<JS::Int16Array>, GC::Ref<JS::Int32Array>, GC::Ref<JS::Uint8Array>, GC::Ref<JS::Uint16Array>, GC::Ref<JS::Uint32Array>, GC::Ref<JS::Uint8ClampedArray>, GC::Ref<JS::BigInt64Array>, GC::Ref<JS::BigUint64Array>, GC::Ref<JS::Float16Array>, GC::Ref<JS::Float32Array>, GC::Ref<JS::Float64Array>, GC::Ref<JS::DataView>, GC::Ref<JS::ArrayBuffer>, GC::Ref<XHR::FormData>, GC::Ref<DOMURL::URLSearchParams>, String, Empty>> body {};
    Optional<RequestCache> cache {};
    Optional<RequestCredentials> credentials {};
    Optional<RequestDuplex> duplex {};
    Optional<Variant<Vector<Vector<String>>, OrderedHashMap<String, String>>> headers {};
    Optional<String> integrity {};
    Optional<bool> keepalive {};
    Optional<String> method {};
    Optional<RequestMode> mode {};
    Optional<RequestPriority> priority {};
    Optional<RequestRedirect> redirect {};
    Optional<String> referrer {};
    Optional<ReferrerPolicy> referrer_policy {};
    Optional<GC::Ptr<DOM::AbortSignal>> signal {};
    Optional<JS::Value> window {};
};

JS::ThrowCompletionOr<RequestInit> convert_to_idl_value_for_request_init(JS::VM&, JS::Value);

} // namespace Web::Bindings
