/*
 * Copyright 2024 Rive
 */

#ifndef _RIVE_FOCUS_NODE_HPP_
#define _RIVE_FOCUS_NODE_HPP_

#include "rive/input/focusable.hpp"
#include "rive/math/aabb.hpp"
#include "rive/refcnt.hpp"
#include <cstdint>
#include <string>
#include <vector>

namespace rive
{

class FocusManager; // Forward declaration

enum class EdgeBehavior : uint8_t
{
    parentScope = 0, // Focus exits to parent scope's next focusable
    closedLoop = 1,  // Focus wraps from last to first within this scope
    stop = 2,        // Focus stays on boundary element
};

class FocusNode : public RefCnt<FocusNode>
{
public:
    FocusNode(Focusable* focusable = nullptr) : m_focusable(focusable) {}

    // === Focusable ===

    Focusable* focusable() const { return m_focusable; }
    void setFocusable(Focusable* focusable) { m_focusable = focusable; }
    void clearFocusable() { m_focusable = nullptr; }

    // === Properties (bitfield-backed) ===

    // Master switch: if false, node cannot receive focus at all
    bool canFocus() const { return m_flags & Flag::kCanFocus; }
    void canFocus(bool value) { setFlag(Flag::kCanFocus, value); }

    // Can receive focus via pointer/touch click
    bool canTouch() const { return m_flags & Flag::kCanTouch; }
    void canTouch(bool value) { setFlag(Flag::kCanTouch, value); }

    // Included in tab traversal
    bool canTraverse() const { return m_flags & Flag::kCanTraverse; }
    void canTraverse(bool value) { setFlag(Flag::kCanTraverse, value); }

    // True if this node or any descendant currently has focus
    // (set by FocusManager during focus transitions)
    bool hasFocus() const { return m_flags & Flag::kHasFocus; }

    // Note: A node with canFocus=true but canTouch=false and canTraverse=false
    // can still be focused programmatically (via script) and receives text
    // input.

    // Scope status is implicit: a node with children is a scope.
    // EdgeBehavior only applies to scopes (nodes with children).
    EdgeBehavior edgeBehavior() const
    {
        return static_cast<EdgeBehavior>((m_flags >> edgeBehaviorShift) &
                                         edgeBehaviorMask);
    }
    void edgeBehavior(EdgeBehavior edge)
    {
        m_flags = (m_flags & ~(edgeBehaviorMask << edgeBehaviorShift)) |
                  (static_cast<uint8_t>(edge) << edgeBehaviorShift);
    }

    int tabIndex() const { return m_tabIndex; }
    void tabIndex(int value) { m_tabIndex = static_cast<int16_t>(value); }

    // Debug name (not required to be unique)
    const std::string& name() const { return m_name; }
    void name(const std::string& value) { m_name = value; }

    // === World Bounds (for directional navigation) ===

    // World bounds in root artboard space, used for spatial navigation.
    // Set during update cycle by owner (TextInput, Dart, etc).
    const AABB& worldBounds() const { return m_worldBounds; }
    void worldBounds(const AABB& bounds) { m_worldBounds = bounds; }

    // Check if bounds are available (not empty/invalid)
    bool hasWorldBounds() const { return !m_worldBounds.isEmptyOrNaN(); }

    // Clear bounds (mark as unavailable)
    void clearWorldBounds() { m_worldBounds = AABB(); }

    // === Hierarchy ===

    FocusNode* parent() const { return m_parent; }
    const std::vector<rcp<FocusNode>>& children() const { return m_children; }
    FocusManager* manager() const { return m_manager; }
    bool isScope() const { return !m_children.empty(); }

    void addChild(rcp<FocusNode> child);
    void removeChild(rcp<FocusNode> child);

    // Remove this node from its current parent (used internally)
    void removeFromParent();

    // === Input Handling (delegates to Focusable) ===

    bool keyInput(Key key,
                  KeyModifiers modifiers,
                  bool isPressed,
                  bool isRepeat)
    {
        return m_focusable
                   ? m_focusable->keyInput(key, modifiers, isPressed, isRepeat)
                   : false;
    }

    bool textInput(const std::string& text)
    {
        return m_focusable ? m_focusable->textInput(text) : false;
    }

    void focused()
    {
        if (m_focusable)
        {
            m_focusable->focused();
        }
    }

    void blurred()
    {
        if (m_focusable)
        {
            m_focusable->blurred();
        }
    }

private:
    friend class FocusManager;

    // Used by FocusManager to update focus state
    void setHasFocus(bool value) { setFlag(Flag::kHasFocus, value); }

    enum Flag : uint8_t
    {
        kCanFocus = 1 << 0,    // default: true
        kCanTouch = 1 << 1,    // default: true
        kCanTraverse = 1 << 2, // default: true
        // bits 3-4: EdgeBehavior (2 bits)
        kHasFocus = 1 << 5, // true if this node or descendant has focus
    };
    static constexpr uint8_t edgeBehaviorShift = 3;
    static constexpr uint8_t edgeBehaviorMask = 0x3;
    static constexpr uint8_t defaultFlags =
        Flag::kCanFocus | Flag::kCanTouch | Flag::kCanTraverse;

    void setFlag(Flag flag, bool value)
    {
        if (value)
        {
            m_flags |= flag;
        }
        else
        {
            m_flags &= ~flag;
        }
    }

    Focusable* m_focusable = nullptr;
    FocusNode* m_parent = nullptr;
    FocusManager* m_manager = nullptr;
    std::vector<rcp<FocusNode>> m_children;
    std::string m_name;
    AABB m_worldBounds; // Default empty (invalid) - hasWorldBounds() returns
                        // false
    uint8_t m_flags = defaultFlags;
    int16_t m_tabIndex = 0;
};

} // namespace rive

#endif
