// Hierarchy reader for parsing UI dump JSON files
#pragma once

#include <nlohmann/json.hpp>
#include <string>
#include <vector>
#include <optional>
#include <filesystem>

namespace mosis::test {

// Element bounds from hierarchy
struct ElementBounds {
    float x = 0;
    float y = 0;
    float width = 0;
    float height = 0;

    // Get center point
    int centerX() const { return static_cast<int>(x + width / 2); }
    int centerY() const { return static_cast<int>(y + height / 2); }
};

// Element info from hierarchy
struct ElementInfo {
    std::string tag;
    std::string id;
    std::vector<std::string> classes;
    ElementBounds bounds;
    bool visible = false;
    std::string text;
};

// Reads and parses UI hierarchy dump files
class HierarchyReader {
public:
    HierarchyReader() = default;

    // Set the path to the hierarchy file
    void SetHierarchyPath(const std::filesystem::path& path);

    // Reload the hierarchy from file
    bool Reload();

    // Check if hierarchy is loaded
    bool IsLoaded() const { return m_loaded; }

    // Get screen URL from hierarchy
    std::string GetScreen() const;

    // Get screen name (filename only) from hierarchy
    std::string GetScreenName() const;

    // Get resolution from hierarchy
    int GetWidth() const;
    int GetHeight() const;

    // Get all elements (for debugging)
    std::vector<ElementInfo> GetAllElements() const;

    // Find element by ID
    std::optional<ElementInfo> FindById(const std::string& id) const;

    // Find elements by class name
    std::vector<ElementInfo> FindByClass(const std::string& className) const;

    // Find elements by tag name
    std::vector<ElementInfo> FindByTag(const std::string& tagName) const;

    // Find first visible element matching a predicate
    std::optional<ElementInfo> FindFirst(
        std::function<bool(const ElementInfo&)> predicate) const;

    // Get raw JSON (for debugging)
    const nlohmann::json& GetJson() const { return m_json; }

private:
    // Parse element info from JSON node
    ElementInfo ParseElement(const nlohmann::json& j) const;

    // Recursively search for elements
    void SearchElements(const nlohmann::json& j,
                       std::function<bool(const ElementInfo&)> predicate,
                       std::vector<ElementInfo>& results) const;

    std::filesystem::path m_path;
    nlohmann::json m_json;
    bool m_loaded = false;
};

} // namespace mosis::test
