#pragma once

#include <string>
#include <vector>
#include <unordered_set>
#include <functional>
#include "./types.hpp"

extern "C" {
#include <tree_sitter/api.h>
}

namespace lsp::language::ast
{
    struct TokenInfo
    {
        Location location;
        std::string type; // 节点类型 (如 "identifier", "number")
        std::string text; // Token 文本内容
        bool is_named = false;
        uint32_t depth = 0;

        std::string parent_type; // 父节点类型
        uint32_t child_index = 0; // 在父节点中的索引
        uint32_t sibling_count = 0; // 兄弟节点总数

        bool is_error = false; // 是否是错误节点
        bool is_missing = false; // 是否是缺失节点
    };

    // ===== Token 收集选项 =====

    struct TokenCollectionOptions
    {
        // 基本过滤选项
        bool include_anonymous = true; // 包含匿名节点 (如括号、分号等)
        bool include_comments = false; // 包含注释节点
        bool include_whitespace = false; // 包含空白节点
        bool include_errors = true; // 包含错误节点
        bool include_missing = true; // 包含缺失节点

        // 深度控制
        uint32_t max_depth = UINT32_MAX; // 最大遍历深度
        uint32_t min_depth = 0; // 最小遍历深度

        // 类型过滤
        std::unordered_set<std::string> include_types; // 仅包含这些类型 (为空则包含所有)
        std::unordered_set<std::string> exclude_types; // 排除这些类型

        // 文本过滤
        bool skip_empty_text = false; // 跳过空文本节点
        uint32_t min_text_length = 0; // 最小文本长度
        uint32_t max_text_length = UINT32_MAX; // 最大文本长度

        // 位置过滤
        bool has_location_filter = false; // 是否启用位置过滤
        uint32_t filter_start_line = 0; // 过滤起始行
        uint32_t filter_end_line = UINT32_MAX; // 过滤结束行

        // 自定义过滤器
        std::function<bool(const TokenInfo&)> custom_filter;

        TokenCollectionOptions() = default;

        // 便捷构造函数
        static TokenCollectionOptions OnlyNamed()
        {
            TokenCollectionOptions opts;
            opts.include_anonymous = false;
            return opts;
        }

        static TokenCollectionOptions WithComments()
        {
            TokenCollectionOptions opts;
            opts.include_comments = true;
            return opts;
        }

        static TokenCollectionOptions OnlyTypes(const std::vector<std::string>& types)
        {
            TokenCollectionOptions opts;
            opts.include_types = std::unordered_set<std::string>(types.begin(), types.end());
            return opts;
        }

        static TokenCollectionOptions ExcludeTypes(const std::vector<std::string>& types)
        {
            TokenCollectionOptions opts;
            opts.exclude_types = std::unordered_set<std::string>(types.begin(), types.end());
            return opts;
        }

        static TokenCollectionOptions InRange(uint32_t start_line, uint32_t end_line)
        {
            TokenCollectionOptions opts;
            opts.has_location_filter = true;
            opts.filter_start_line = start_line;
            opts.filter_end_line = end_line;
            return opts;
        }
    };

    // ===== Token 收集器类 =====

    class TokenCollector
    {
    public:
        explicit TokenCollector(const TokenCollectionOptions& options = {});
        ~TokenCollector() = default;
        TokenCollector(const TokenCollector&) = delete;
        TokenCollector& operator=(const TokenCollector&) = delete;
        TokenCollector(TokenCollector&&) = default;
        TokenCollector& operator=(TokenCollector&&) = default;

        std::vector<TokenInfo> Collect(TSNode root, const std::string& source);
        std::vector<TokenInfo> CollectByType(TSNode root, const std::string& source, const std::vector<std::string>& types);
        std::vector<TokenInfo> CollectInRange(TSNode root, const std::string& source, uint32_t start_line, uint32_t end_line);
        std::vector<TokenInfo> CollectLeafNodes(TSNode root, const std::string& source);

        std::vector<TokenInfo> FindTokensAtPosition(TSNode root, const std::string& source, uint32_t line, uint32_t column);
        std::vector<TokenInfo> FindTokensByText(TSNode root, const std::string& source, const std::string& text, bool exact_match = true);
        std::vector<TokenInfo> FindTokensBy(TSNode root, const std::string& source, std::function<bool(const TokenInfo&)> predicate);

        uint32_t CountTokensByType(TSNode root, const std::string& source, const std::string& type);
        std::vector<std::string> GetUniqueTypes(TSNode root, const std::string& source);

        void SetOptions(const TokenCollectionOptions& options) { options_ = options; }
        const TokenCollectionOptions& GetOptions() const { return options_; }

    private:
        void CollectRecursive(TSNode node, const std::string& source, std::vector<TokenInfo>& tokens, uint32_t depth, TSNode parent);
        bool ShouldCollectNode(const TokenInfo& info) const;
        void FillTokenInfo(TokenInfo& info, TSNode node, const std::string& source, uint32_t depth, TSNode parent) const;
        bool IsCommentNode(const std::string& type) const;
        bool IsWhitespaceNode(const std::string& type) const;
        bool IsLocationInRange(const Location& loc) const;

    private:
        TokenCollectionOptions options_;
    };

    inline std::vector<TokenInfo> CollectNamedTokens(TSNode root, const std::string& source)
    {
        return TokenCollector(TokenCollectionOptions::OnlyNamed()).Collect(root, source);
    }

    inline std::vector<TokenInfo> CollectTokensOfType(TSNode root, const std::string& source, const std::string& type)
    {
        return TokenCollector().CollectByType(root, source, { type });
    }

}
