/*
 * Copyright (c) 2026-present, the Ladybird developers.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

/* Generated with cbindgen:0.29.2 */

#include <stdint.h>
#include <stddef.h>

namespace Web {
namespace CSS {
namespace SelectorFFI {

enum class TagNameMatchingMode : uint8_t {
    Normal,
    Fast,
};

enum class Direction : uint8_t {
    None,
    LeftToRight,
    RightToLeft,
    Other,
};

enum class Combinator : uint8_t {
    None,
    ImmediateChild,
    Descendant,
    NextSibling,
    SubsequentSibling,
    Column,
    PseudoElement,
};

enum class HasCacheResult : uint8_t {
    NotCached,
    NotMatched,
    Matched,
};

enum class SimpleSelectorType : uint8_t {
    Universal,
    TagName,
    Id,
    Class,
    Attribute,
    PseudoClass,
    PseudoElement,
    Nesting,
    Invalid,
};

enum class NamespaceType : uint8_t {
    Default,
    None,
    Any,
    Named,
};

enum class AttributeMatchType : uint8_t {
    HasAttribute,
    ExactValue,
    ContainsWord,
    ContainsString,
    StartsWithSegment,
    StartsWithString,
    EndsWithString,
};

enum class AttributeCaseType : uint8_t {
    Default,
    Sensitive,
    Insensitive,
};

enum class PseudoElementValueType : uint8_t {
    None,
    CompoundSelector,
    Identifiers,
    TransitionName,
};

struct RustSelector;

struct StringView {
    const uint16_t *data;
    size_t length;
};

struct ElementAndShadowHost {
    const void *element;
    const void *shadow_host;
};

struct SimpleSelector {
    SimpleSelectorType selector_type;
    const void *cxx_simple_selector;
    NamespaceType namespace_type;
    StringView namespace_;
    StringView name;
    StringView lowercase_name;
    AttributeMatchType attribute_match_type;
    AttributeCaseType attribute_case_type;
    StringView attribute_value;
    uint8_t pseudo_class;
    int32_t an_plus_b_step_size;
    int32_t an_plus_b_offset;
    const RustSelector *const *argument_selectors;
    size_t argument_selector_count;
    const StringView *languages;
    size_t language_count;
    Direction direction;
    StringView identifier;
    const int64_t *levels;
    size_t level_count;
    uint8_t pseudo_element;
    PseudoElementValueType pseudo_element_value_type;
    const RustSelector *pseudo_element_selector;
    const StringView *pseudo_element_identifiers;
    size_t pseudo_element_identifier_count;
    bool transition_name_is_universal;
    StringView transition_name;
};

struct CompoundSelector {
    Combinator combinator;
    const SimpleSelector *simple_selectors;
    size_t simple_selector_count;
};

struct Selector {
    const void *cxx_selector;
    const CompoundSelector *compound_selectors;
    size_t compound_selector_count;
};

extern "C" {

extern bool selector_ffi_matches_universal(void *context, const void *element, const void *cxx_simple_selector);

extern bool selector_ffi_matches_tag_name(void *context,
                                          const void *element,
                                          const void *cxx_simple_selector,
                                          TagNameMatchingMode matching_mode);

extern bool selector_ffi_matches_id(const void *element, const void *cxx_simple_selector);

extern bool selector_ffi_matches_class(const void *element, const void *cxx_simple_selector);

extern bool selector_ffi_matches_attribute(void *context, const void *element, const void *cxx_simple_selector);

extern bool selector_ffi_matches_pseudo_class(const void *element, uint8_t pseudo_class);

extern bool selector_ffi_matches_language(const void *element, StringView language);

extern bool selector_ffi_matches_direction(const void *element, Direction direction);

extern bool selector_ffi_matches_state(const void *element, const void *cxx_simple_selector);

extern bool selector_ffi_matches_heading(const void *element, const int64_t *levels, size_t level_count);

extern const void *selector_ffi_parent_element(const void *element, const void *shadow_host);

extern const void *selector_ffi_parent_element_in_light_tree(const void *element);

extern const void *selector_ffi_previous_element_sibling(const void *element);

extern const void *selector_ffi_next_element_sibling(const void *element);

extern const void *selector_ffi_first_element_child(const void *element);

extern const void *selector_ffi_first_element_descendant(const void *element);

extern const void *selector_ffi_next_element_descendant(const void *element, const void *root);

extern bool selector_ffi_has_no_element_or_nonempty_text_children(const void *element);

extern bool selector_ffi_has_same_type(const void *first, const void *second);

extern bool selector_ffi_is_document_root(const void *element);

extern bool selector_ffi_is_shadow_tree_slot(const void *element);

extern ElementAndShadowHost selector_ffi_slotted_parent(void *context, const void *element);

extern ElementAndShadowHost selector_ffi_part_parent(void *context,
                                                     const void *element,
                                                     const StringView *identifiers,
                                                     size_t identifier_count,
                                                     bool allow_same_shadow_root_scope,
                                                     const void *shadow_host);

extern void selector_ffi_note_structural_pseudo_class(void *context, const void *element, uint8_t pseudo_class);

extern void selector_ffi_note_has_pseudo_class(void *context, const void *element);

extern void selector_ffi_note_sibling_combinator(void *context,
                                                 const void *element,
                                                 Combinator combinator,
                                                 size_t sibling_invalidation_distance);

extern void selector_ffi_note_has_sibling_combinator_anchor(void *context, const void *anchor);

extern void selector_ffi_note_has_sibling_combinator_element(void *context, const void *element);

extern void selector_ffi_note_has_scope_element(void *context, const void *element);

extern void selector_ffi_set_inside_has_argument(void *context, bool value);

extern HasCacheResult selector_ffi_has_cache_get(void *context, uint64_t selector_id, const void *anchor);

extern void selector_ffi_has_cache_set(void *context, uint64_t selector_id, const void *anchor, bool result);

extern bool selector_ffi_should_reject_has_argument(void *context, const void *selector, const void *anchor);

/// # Safety
///
/// `selector`, every transitively referenced array, string, and `RustSelector` handle must be
/// properly aligned and valid for reads for the duration of this call. Every enum field must
/// contain a valid discriminant.
///
/// `FfiSelector::cxx_selector` and every `FfiSimpleSelector::cxx_simple_selector` must remain valid
/// until the returned handle is passed to `rust_selector_destroy`. The returned handle must be
/// destroyed exactly once.
RustSelector *rust_selector_create(const Selector *selector);

/// # Safety
/// `selector` must be a pointer returned by `rust_selector_create` that has not already been destroyed.
void rust_selector_destroy(RustSelector *selector);

/// # Safety
/// `selector` must point to a live handle returned by `rust_selector_create`.
uint8_t rust_selector_target_pseudo_element(const RustSelector *selector);

/// # Safety
/// The `selector` handle must have been returned by `rust_selector_create`. `element` and a
/// non-null `shadow_host` must point to C++ DOM elements, a non-null `scope` must point to a C++
/// DOM parent node, and `context` must point to a C++ Rust matching context. All referenced objects
/// must remain valid for this call.
bool rust_selector_matches(const RustSelector *selector,
                           const void *element,
                           uint8_t pseudo_element,
                           const void *shadow_host,
                           void *context,
                           const void *scope,
                           bool collects_selector_involvement_metadata,
                           bool inside_has_argument);

/// # Safety
/// The `selector` handle must have been returned by `rust_selector_create`. `element` and a
/// non-null `shadow_host` must point to C++ DOM elements, a non-null `scope` must point to a C++
/// DOM parent node, and `context` must point to a C++ Rust matching context. All referenced objects
/// must remain valid for this call.
bool rust_selector_matches_originating_element(const RustSelector *selector,
                                               uint8_t pseudo_element,
                                               const void *element,
                                               const void *shadow_host,
                                               void *context,
                                               const void *scope,
                                               bool collects_selector_involvement_metadata,
                                               bool inside_has_argument);

}  // extern "C"

}  // namespace SelectorFFI
}  // namespace CSS
}  // namespace Web
