#include <spdlog/spdlog.h>
#include "./conversion.hpp"

namespace lsp::service::symbol
{
    FileSymbolIndex BuildFromEditingTable(const EditingSymbolTable& editing_table)
    {
        FileSymbolIndex index;

        index.uri = editing_table.uri;
        index.file_type = editing_table.file_type;
        index.file_path = editing_table.file_path;

        if (editing_table.symbol_table)
            ExtractSymbols(index, *editing_table.symbol_table);

        return index;
    }

    void ExtractSymbols(FileSymbolIndex& index, const language::symbol::SymbolTable& table)
    {
        auto all_defs = table.GetAllDefinitions();
        if (all_defs.empty())
            return;

        // 根据文件类型提取不同的符号
        switch (index.file_type)
        {
        case TsfFileType::kUnit:
            ExtractUnitSymbols(index, table, all_defs);
            break;

        case TsfFileType::kClass:
            ExtractClassSymbols(index, table, all_defs);
            break;

        case TsfFileType::kFunction:
            ExtractFunctionSymbols(index, table, all_defs);
            break;

        case TsfFileType::kScript:
            ExtractScriptSymbols(index, table, all_defs);
            break;
        }
    }

    void ExtractUnitSymbols(FileSymbolIndex& index, const language::symbol::SymbolTable& table, const std::vector<const language::symbol::SymbolDefinition*>& all_defs)
    {
        for (const auto* def : all_defs)
        {
            if (def->kind == language::symbol::SymbolKind::Module)
            {
                index.primary_symbol = def->name;
                index.primary_kind = def->kind;
                break;
            }
        }

        // 提取顶层函数（没有父符号的 Function）
        for (const auto* def : all_defs)
        {
            if (def->kind == language::symbol::SymbolKind::Function && !def->parent_id)
            {
                MemberSymbol member;
                member.name = def->name;
                member.kind = def->kind;
                member.return_type = def->type_hint;

                index.exported_symbols.push_back(std::move(member));
            }
        }
    }

    void ExtractClassSymbols(FileSymbolIndex& index, const language::symbol::SymbolTable& table, const std::vector<const language::symbol::SymbolDefinition*>& all_defs)
    {
        // 查找 Class 定义
        const language::symbol::SymbolDefinition* class_def = nullptr;
        for (const auto* def : all_defs)
        {
            if (def->kind == language::symbol::SymbolKind::Class)
            {
                index.primary_symbol = def->name;
                index.primary_kind = def->kind;
                class_def = def;
                break;
            }
        }

        if (!class_def)
            return;

        // 提取类的所有成员
        auto children = table.GetChildren(class_def->id);
        for (auto child_id : children)
        {
            const auto* member_def = table.GetDefinition(child_id);
            if (!member_def)
                continue;

            // 只提取 public 成员
            if (member_def->access_modifier && *member_def->access_modifier != language::ast::AccessModifier::kPublic)
                continue;

            // 过滤掉私有成员
            if (member_def->kind == language::symbol::SymbolKind::Method ||
                member_def->kind == language::symbol::SymbolKind::Property ||
                member_def->kind == language::symbol::SymbolKind::Field ||
                member_def->kind == language::symbol::SymbolKind::Constructor)
            {
                MemberSymbol member;
                member.name = member_def->name;
                member.kind = member_def->kind;
                member.return_type = member_def->type_hint;
                member.access = member_def->access_modifier;
                member.is_class_method = member_def->is_class_method;
                member.parameters = ExtractFunctionParameters(table, member_def->id);

                index.exported_symbols.push_back(std::move(member));
            }
        }
    }

    void ExtractFunctionSymbols(FileSymbolIndex& index, const language::symbol::SymbolTable& table, const std::vector<const language::symbol::SymbolDefinition*>& all_defs)
    {
        // Function 文件的主符号就是函数本身
        for (const auto* def : all_defs)
        {
            if (def->kind == language::symbol::SymbolKind::Function && !def->parent_id)
            {
                index.primary_symbol = def->name;
                index.primary_kind = def->kind;

                MemberSymbol member;
                member.name = def->name;
                member.kind = def->kind;
                member.return_type = def->type_hint;
                member.parameters = ExtractFunctionParameters(table, def->id);
                index.exported_symbols.push_back(std::move(member));
                break;
            }
        }
    }

    void ExtractScriptSymbols(FileSymbolIndex& index, const language::symbol::SymbolTable& table, const std::vector<const language::symbol::SymbolDefinition*>& all_defs)
    {
        index.primary_symbol = "Script";
        index.primary_kind = language::symbol::SymbolKind::Module;

        for (const auto* def : all_defs)
        {
            if (def->kind == language::symbol::SymbolKind::Function && !def->parent_id)
            {
                MemberSymbol member;
                member.name = def->name;
                member.kind = def->kind;
                member.return_type = def->type_hint;
                member.parameters = ExtractFunctionParameters(table, def->id);

                index.exported_symbols.push_back(std::move(member));
            }
        }
    }

    std::vector<symbol::Parameter> ExtractFunctionParameters(const language::symbol::SymbolTable& table, language::symbol::SymbolId function_id)
    {
        std::vector<symbol::Parameter> params;

        auto children = table.GetChildren(function_id);
        for (auto child_id : children)
        {
            const auto* child_def = table.GetDefinition(child_id);
            if (!child_def)
                continue;

            if (child_def->kind == language::symbol::SymbolKind::Variable)
            {
                symbol::Parameter param;
                param.name = child_def->name;
                param.type = child_def->type_hint.value_or("");
                param.has_default = false;
                params.push_back(std::move(param));
            }
        }

        return params;
    }

}
