#pragma once

#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/Variant.h>
#include <AK/Vector.h>
#include <LibJS/Forward.h>
#include <LibJS/Runtime/Value.h>
#include <LibWeb/Bindings/MediaStreamConstraints.h>
#include <LibWeb/WebIDL/Types.h>

namespace Web::Bindings {

struct ConstrainDOMStringParameters {
    Optional<Variant<String, Vector<String>>> exact {};
    Optional<Variant<String, Vector<String>>> ideal {};
};

JS::ThrowCompletionOr<ConstrainDOMStringParameters> convert_to_idl_value_for_constrain_dom_string_parameters(JS::VM&, JS::Value);

struct DoubleRange {
    Optional<double> max {};
    Optional<double> min {};
};

JS::ThrowCompletionOr<DoubleRange> convert_to_idl_value_for_double_range(JS::VM&, JS::Value);

struct ConstrainDoubleRange : public DoubleRange {
    Optional<double> exact {};
    Optional<double> ideal {};
};

JS::ThrowCompletionOr<ConstrainDoubleRange> convert_to_idl_value_for_constrain_double_range(JS::VM&, JS::Value);

struct ULongRange {
    Optional<WebIDL::UnsignedLong> max {};
    Optional<WebIDL::UnsignedLong> min {};
};

JS::ThrowCompletionOr<ULongRange> convert_to_idl_value_for_u_long_range(JS::VM&, JS::Value);

struct ConstrainULongRange : public ULongRange {
    Optional<WebIDL::UnsignedLong> exact {};
    Optional<WebIDL::UnsignedLong> ideal {};
};

JS::ThrowCompletionOr<ConstrainULongRange> convert_to_idl_value_for_constrain_u_long_range(JS::VM&, JS::Value);

struct ConstrainBooleanParameters {
    Optional<bool> exact {};
    Optional<bool> ideal {};
};

JS::ThrowCompletionOr<ConstrainBooleanParameters> convert_to_idl_value_for_constrain_boolean_parameters(JS::VM&, JS::Value);

struct ConstrainBooleanOrDOMStringParameters {
    Optional<Variant<bool, String>> exact {};
    Optional<Variant<bool, String>> ideal {};
};

JS::ThrowCompletionOr<ConstrainBooleanOrDOMStringParameters> convert_to_idl_value_for_constrain_boolean_or_dom_string_parameters(JS::VM&, JS::Value);

struct MediaTrackConstraintSet {
    Optional<Variant<double, ConstrainDoubleRange>> aspect_ratio {};
    Optional<Variant<bool, ConstrainBooleanParameters>> auto_gain_control {};
    Optional<Variant<bool, ConstrainBooleanParameters>> background_blur {};
    Optional<Variant<WebIDL::UnsignedLong, ConstrainULongRange>> channel_count {};
    Optional<Variant<String, Vector<String>, ConstrainDOMStringParameters>> device_id {};
    Optional<Variant<bool, String, ConstrainBooleanOrDOMStringParameters>> echo_cancellation {};
    Optional<Variant<String, Vector<String>, ConstrainDOMStringParameters>> facing_mode {};
    Optional<Variant<double, ConstrainDoubleRange>> frame_rate {};
    Optional<Variant<String, Vector<String>, ConstrainDOMStringParameters>> group_id {};
    Optional<Variant<WebIDL::UnsignedLong, ConstrainULongRange>> height {};
    Optional<Variant<double, ConstrainDoubleRange>> latency {};
    Optional<Variant<bool, ConstrainBooleanParameters>> noise_suppression {};
    Optional<Variant<String, Vector<String>, ConstrainDOMStringParameters>> resize_mode {};
    Optional<Variant<WebIDL::UnsignedLong, ConstrainULongRange>> sample_rate {};
    Optional<Variant<WebIDL::UnsignedLong, ConstrainULongRange>> sample_size {};
    Optional<Variant<WebIDL::UnsignedLong, ConstrainULongRange>> width {};
};

JS::ThrowCompletionOr<MediaTrackConstraintSet> convert_to_idl_value_for_media_track_constraint_set(JS::VM&, JS::Value);

struct MediaTrackConstraints : public MediaTrackConstraintSet {
    Optional<Vector<MediaTrackConstraintSet>> advanced {};
};

JS::ThrowCompletionOr<MediaTrackConstraints> convert_to_idl_value_for_media_track_constraints(JS::VM&, JS::Value);

struct MediaStreamConstraints {
    Variant<bool, MediaTrackConstraints> audio { Variant<bool, MediaTrackConstraints> { false } };
    Variant<bool, MediaTrackConstraints> video { Variant<bool, MediaTrackConstraints> { false } };
};

JS::ThrowCompletionOr<MediaStreamConstraints> convert_to_idl_value_for_media_stream_constraints(JS::VM&, JS::Value);

struct MediaTrackSupportedConstraints {
    bool aspect_ratio { true };
    bool auto_gain_control { true };
    bool background_blur { true };
    bool channel_count { true };
    bool device_id { true };
    bool echo_cancellation { true };
    bool facing_mode { true };
    bool frame_rate { true };
    bool group_id { true };
    bool height { true };
    bool latency { true };
    bool noise_suppression { true };
    bool resize_mode { true };
    bool sample_rate { true };
    bool sample_size { true };
    bool width { true };
};

JS::ThrowCompletionOr<MediaTrackSupportedConstraints> convert_to_idl_value_for_media_track_supported_constraints(JS::VM&, JS::Value);

struct MediaTrackCapabilities {
    Optional<DoubleRange> aspect_ratio {};
    Optional<Vector<bool>> auto_gain_control {};
    Optional<Vector<bool>> background_blur {};
    Optional<ULongRange> channel_count {};
    Optional<String> device_id {};
    Optional<Vector<Variant<bool, String>>> echo_cancellation {};
    Optional<Vector<String>> facing_mode {};
    Optional<DoubleRange> frame_rate {};
    Optional<String> group_id {};
    Optional<ULongRange> height {};
    Optional<DoubleRange> latency {};
    Optional<Vector<bool>> noise_suppression {};
    Optional<Vector<String>> resize_mode {};
    Optional<ULongRange> sample_rate {};
    Optional<ULongRange> sample_size {};
    Optional<ULongRange> width {};
};

JS::ThrowCompletionOr<MediaTrackCapabilities> convert_to_idl_value_for_media_track_capabilities(JS::VM&, JS::Value);

struct MediaTrackSettings {
    Optional<double> aspect_ratio {};
    Optional<bool> auto_gain_control {};
    Optional<bool> background_blur {};
    Optional<WebIDL::UnsignedLong> channel_count {};
    Optional<String> device_id {};
    Optional<Variant<bool, String>> echo_cancellation {};
    Optional<String> facing_mode {};
    Optional<double> frame_rate {};
    Optional<String> group_id {};
    Optional<WebIDL::UnsignedLong> height {};
    Optional<double> latency {};
    Optional<bool> noise_suppression {};
    Optional<String> resize_mode {};
    Optional<WebIDL::UnsignedLong> sample_rate {};
    Optional<WebIDL::UnsignedLong> sample_size {};
    Optional<WebIDL::UnsignedLong> width {};
};

JS::ThrowCompletionOr<MediaTrackSettings> convert_to_idl_value_for_media_track_settings(JS::VM&, JS::Value);

} // namespace Web::Bindings
