/*
 * 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
class ListenerInvocation;

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); }

#ifdef WITH_RIVE_TOOLS
    // Only at edit time, we push down the collapse status of the nodes because
    // we can't get the FocusData node from the FocusNode
    bool isCollapsed() const { return m_isCollapsed; }
    void isCollapsed(bool value) { m_isCollapsed = value; }
#endif
    // 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;
    }

    bool gamepadDispatch(
        const ListenerInvocation& invocation,
        ScriptedDrawable** outDispatchedScriptedDrawable = nullptr)
    {
        return m_focusable
                   ? m_focusable->gamepadDispatch(invocation,
                                                  outDispatchedScriptedDrawable)
                   : 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;
#ifdef WITH_RIVE_TOOLS
    bool m_isCollapsed = false;
#endif
};

} // namespace rive

#endif
