#pragma once

#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/Utf16String.h>
#include <AK/Vector.h>
#include <LibGC/Ptr.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>
#include <LibWeb/Bindings/MediaCapabilities.h>
#include <LibWeb/Bindings/MediaKeySystemAccess.h>
#include <LibWeb/Forward.h>
#include <LibWeb/WebIDL/Types.h>

namespace Web::Bindings {

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

private:
};

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

private:
    JS_DECLARE_NATIVE_FUNCTION(decoding_info);
};

enum class MediaDecodingType : u8 {
    File,
    MediaSource,
    Webrtc,
};

JS::ThrowCompletionOr<MediaDecodingType> convert_to_idl_value_for_media_decoding_type(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(MediaDecodingType);

enum class MediaEncodingType : u8 {
    Record,
    Webrtc,
};

JS::ThrowCompletionOr<MediaEncodingType> convert_to_idl_value_for_media_encoding_type(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(MediaEncodingType);

enum class HdrMetadataType : u8 {
    Smptest2086,
    Smptest209410,
    Smptest209440,
};

JS::ThrowCompletionOr<HdrMetadataType> convert_to_idl_value_for_hdr_metadata_type(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(HdrMetadataType);

enum class ColorGamut : u8 {
    Srgb,
    P3,
    Rec2020,
};

JS::ThrowCompletionOr<ColorGamut> convert_to_idl_value_for_color_gamut(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(ColorGamut);

enum class TransferFunction : u8 {
    Srgb,
    Pq,
    Hlg,
};

JS::ThrowCompletionOr<TransferFunction> convert_to_idl_value_for_transfer_function(JS::VM&, JS::Value);

Utf16String idl_enum_to_string(TransferFunction);

struct VideoConfiguration {
    WebIDL::UnsignedLongLong bitrate;
    Optional<ColorGamut> color_gamut {};
    String content_type;
    double framerate;
    Optional<bool> has_alpha_channel {};
    Optional<HdrMetadataType> hdr_metadata_type {};
    WebIDL::UnsignedLong height;
    Optional<String> scalability_mode {};
    Optional<bool> spatial_scalability {};
    Optional<TransferFunction> transfer_function {};
    WebIDL::UnsignedLong width;
};

JS::ThrowCompletionOr<VideoConfiguration> convert_to_idl_value_for_video_configuration(JS::VM&, JS::Value);

struct AudioConfiguration {
    Optional<WebIDL::UnsignedLongLong> bitrate {};
    Optional<String> channels {};
    String content_type;
    Optional<WebIDL::UnsignedLong> samplerate {};
    Optional<bool> spatial_rendering {};
};

JS::ThrowCompletionOr<AudioConfiguration> convert_to_idl_value_for_audio_configuration(JS::VM&, JS::Value);

struct MediaConfiguration {
    Optional<AudioConfiguration> audio {};
    Optional<VideoConfiguration> video {};
};

JS::ThrowCompletionOr<MediaConfiguration> convert_to_idl_value_for_media_configuration(JS::VM&, JS::Value);

struct KeySystemTrackConfiguration {
    Optional<String> encryption_scheme { OptionalNone {} };
    String robustness { String {} };
};

JS::ThrowCompletionOr<KeySystemTrackConfiguration> convert_to_idl_value_for_key_system_track_configuration(JS::VM&, JS::Value);

struct MediaCapabilitiesKeySystemConfiguration {
    Optional<KeySystemTrackConfiguration> audio {};
    MediaKeysRequirement distinctive_identifier { MediaKeysRequirement::Optional };
    String init_data_type { String {} };
    String key_system;
    MediaKeysRequirement persistent_state { MediaKeysRequirement::Optional };
    Optional<Vector<String>> session_types {};
    Optional<KeySystemTrackConfiguration> video {};
};

JS::ThrowCompletionOr<MediaCapabilitiesKeySystemConfiguration> convert_to_idl_value_for_media_capabilities_key_system_configuration(JS::VM&, JS::Value);

struct MediaDecodingConfiguration : public MediaConfiguration {
    Optional<MediaCapabilitiesKeySystemConfiguration> key_system_configuration {};
    MediaDecodingType type;
};

JS::ThrowCompletionOr<MediaDecodingConfiguration> convert_to_idl_value_for_media_decoding_configuration(JS::VM&, JS::Value);

struct MediaEncodingConfiguration : public MediaConfiguration {
    MediaEncodingType type;
};

JS::ThrowCompletionOr<MediaEncodingConfiguration> convert_to_idl_value_for_media_encoding_configuration(JS::VM&, JS::Value);

struct MediaCapabilitiesInfo {
    bool power_efficient;
    bool smooth;
    bool supported;
};

JS::ThrowCompletionOr<MediaCapabilitiesInfo> convert_to_idl_value_for_media_capabilities_info(JS::VM&, JS::Value);

struct MediaCapabilitiesDecodingInfo : public MediaCapabilitiesInfo {
    Optional<MediaDecodingConfiguration> configuration {};
    GC::Ptr<EncryptedMediaExtensions::MediaKeySystemAccess> key_system_access {};
};

JS::ThrowCompletionOr<MediaCapabilitiesDecodingInfo> convert_to_idl_value_for_media_capabilities_decoding_info(JS::VM&, JS::Value);

struct MediaCapabilitiesEncodingInfo : public MediaCapabilitiesInfo {
    Optional<MediaEncodingConfiguration> configuration {};
};

JS::ThrowCompletionOr<MediaCapabilitiesEncodingInfo> convert_to_idl_value_for_media_capabilities_encoding_info(JS::VM&, JS::Value);

} // namespace Web::Bindings
