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

namespace lsp::service::symbol::repository
{
    // ==================== 基础操作 ====================

    void Workspace::Add(const FileSymbolIndex& index)
    {
        std::unique_lock lock(mutex_);

        const std::string& name = index.primary_symbol;
        const std::string& path = index.file_path;

        spdlog::debug("Workspace::Add - Adding file: path='{}', name='{}', type={}", path, name, static_cast<int>(index.file_type));

        if (auto it = path_to_symbol_.find(path); it != path_to_symbol_.end())
        {
            const std::string& old_name = it->second;
            spdlog::debug("Workspace::Add - File already exists with name '{}', removing old entry", old_name);

            size_t removed = 0;
            removed += units_.erase(old_name);
            removed += classes_.erase(old_name);
            removed += functions_.erase(old_name);

            if (removed == 0)
            {
                spdlog::warn("Workspace::Add - Old entry '{}' not found in any map", old_name);
            }
        }

        switch (index.file_type)
        {
        case TsfFileType::kUnit:
            units_[name] = index;
            spdlog::debug("Workspace::Add - Added as Unit: '{}'", name);
            break;

        case TsfFileType::kClass:
            classes_[name] = index;
            spdlog::debug("Workspace::Add - Added as Class: '{}'", name);
            break;

        case TsfFileType::kFunction:
            functions_[name] = index;
            spdlog::debug("Workspace::Add - Added as Function: '{}'", name);
            break;

        case TsfFileType::kScript:
            spdlog::debug("Workspace::Add - Script type: '{}' (not stored in type-specific map)", name);
            break;

        default:
            spdlog::warn("Workspace::Add - Unknown file type {} for: {}",
                         static_cast<int>(index.file_type),
                         path);
            // ⚠️ 注意：这里不 return，继续更新 path_to_symbol_
            break;
        }

        path_to_symbol_[path] = name;

        spdlog::debug("Workspace::Add - Successfully added: total files={}", path_to_symbol_.size());
    }

    void Workspace::Remove(const std::string& file_path)
    {
        std::unique_lock lock(mutex_);

        spdlog::debug("Workspace::Remove - Removing file: '{}'", file_path);

        auto it = path_to_symbol_.find(file_path);
        if (it != path_to_symbol_.end())
        {
            const std::string& name = it->second;
            spdlog::debug("Workspace::Remove - Found symbol name: '{}'", name);

            size_t removed = 0;
            if (units_.erase(name))
            {
                spdlog::debug("Workspace::Remove - Removed from units_");
                removed++;
            }
            if (classes_.erase(name))
            {
                spdlog::debug("Workspace::Remove - Removed from classes_");
                removed++;
            }
            if (functions_.erase(name))
            {
                spdlog::debug("Workspace::Remove - Removed from functions_");
                removed++;
            }

            if (removed == 0)
            {
                spdlog::warn("Workspace::Remove - Symbol '{}' not found in any type map (might be Script)", name);
            }
            else if (removed > 1)
            {
                spdlog::error("Workspace::Remove - Symbol '{}' found in {} maps (data inconsistency!)", name, removed);
            }

            path_to_symbol_.erase(it);
            spdlog::debug("Workspace::Remove - Successfully removed: total files={}", path_to_symbol_.size());
        }
        else
        {
            spdlog::warn("Workspace::Remove - File not found: '{}'", file_path);
        }
    }

    void Workspace::Clear()
    {
        std::unique_lock lock(mutex_);

        size_t total = path_to_symbol_.size();
        spdlog::debug("Workspace::Clear - Clearing {} files", total);

        units_.clear();
        classes_.clear();
        functions_.clear();
        path_to_symbol_.clear();

        spdlog::info("Workspace::Clear - Cleared workspace repository");
    }

    size_t Workspace::Count() const
    {
        std::shared_lock lock(mutex_);
        return path_to_symbol_.size();
    }

    bool Workspace::Contains(const std::string& file_path) const
    {
        std::shared_lock lock(mutex_);
        bool exists = path_to_symbol_.find(file_path) != path_to_symbol_.end();
        spdlog::trace("Workspace::Contains - '{}': {}", file_path, exists);
        return exists;
    }

    // ==================== 查找API ====================

    std::optional<FileSymbolIndex> Workspace::FindUnit(const std::string& name) const
    {
        std::shared_lock lock(mutex_);
        auto it = units_.find(name);

        if (it != units_.end())
        {
            spdlog::trace("Workspace::FindUnit - Found unit: '{}'", name);
            return it->second;
        }

        spdlog::trace("Workspace::FindUnit - Unit not found: '{}'", name);
        return std::nullopt;
    }

    std::optional<FileSymbolIndex> Workspace::FindClass(const std::string& name) const
    {
        std::shared_lock lock(mutex_);
        auto it = classes_.find(name);

        if (it != classes_.end())
        {
            spdlog::trace("Workspace::FindClass - Found class: '{}'", name);
            return it->second;
        }

        spdlog::trace("Workspace::FindClass - Class not found: '{}'", name);
        return std::nullopt;
    }

    std::optional<FileSymbolIndex> Workspace::FindFunction(const std::string& name) const
    {
        std::shared_lock lock(mutex_);
        auto it = functions_.find(name);

        if (it != functions_.end())
        {
            spdlog::trace("Workspace::FindFunction - Found function: '{}'", name);
            return it->second;
        }

        spdlog::trace("Workspace::FindFunction - Function not found: '{}'", name);
        return std::nullopt;
    }

    std::optional<FileSymbolIndex> Workspace::FindByPath(const std::string& file_path) const
    {
        std::shared_lock lock(mutex_);

        spdlog::trace("Workspace::FindByPath - Searching: '{}'", file_path);

        auto it = path_to_symbol_.find(file_path);
        if (it == path_to_symbol_.end())
        {
            spdlog::trace("Workspace::FindByPath - Path not found in index");
            return std::nullopt;
        }

        const std::string& name = it->second;
        spdlog::trace("Workspace::FindByPath - Found symbol name: '{}'", name);

        // 在各个map中查找
        if (auto uit = units_.find(name); uit != units_.end())
        {
            spdlog::trace("Workspace::FindByPath - Found in units_");
            return uit->second;
        }
        if (auto cit = classes_.find(name); cit != classes_.end())
        {
            spdlog::trace("Workspace::FindByPath - Found in classes_");
            return cit->second;
        }
        if (auto fit = functions_.find(name); fit != functions_.end())
        {
            spdlog::trace("Workspace::FindByPath - Found in functions_");
            return fit->second;
        }

        spdlog::warn("Workspace::FindByPath - Symbol '{}' in path index but not in any type map (inconsistency or Script type)", name);
        return std::nullopt;
    }

    // ==================== 列表API ====================

    std::vector<FileSymbolIndex> Workspace::Units() const
    {
        std::shared_lock lock(mutex_);

        std::vector<FileSymbolIndex> result;
        result.reserve(units_.size());
        for (const auto& [name, index] : units_)
            result.push_back(index);

        spdlog::trace("Workspace::Units - Returning {} units", result.size());
        return result;
    }

    std::vector<FileSymbolIndex> Workspace::Classes() const
    {
        std::shared_lock lock(mutex_);

        std::vector<FileSymbolIndex> result;
        result.reserve(classes_.size());
        for (const auto& [name, index] : classes_)
            result.push_back(index);

        spdlog::trace("Workspace::Classes - Returning {} classes", result.size());
        return result;
    }

    std::vector<FileSymbolIndex> Workspace::Functions() const
    {
        std::shared_lock lock(mutex_);

        std::vector<FileSymbolIndex> result;
        spdlog::debug(">>>>>>>>>>>>>>>>>>>> {}", functions_.size());
        result.reserve(functions_.size());
        for (const auto& [name, index] : functions_)
            result.push_back(index);

        spdlog::trace("Workspace::Functions - Returning {} functions", result.size());
        return result;
    }

    std::vector<FileSymbolIndex> Workspace::AllFiles() const
    {
        std::shared_lock lock(mutex_);

        spdlog::trace("Workspace::AllFiles - Building list from {} files", path_to_symbol_.size());

        std::vector<FileSymbolIndex> result;
        result.reserve(path_to_symbol_.size());

        size_t not_found_count = 0;

        for (const auto& [path, name] : path_to_symbol_)
        {
            bool found = false;

            if (auto uit = units_.find(name); uit != units_.end())
            {
                result.push_back(uit->second);
                found = true;
            }
            else if (auto cit = classes_.find(name); cit != classes_.end())
            {
                result.push_back(cit->second);
                found = true;
            }
            else if (auto fit = functions_.find(name); fit != functions_.end())
            {
                result.push_back(fit->second);
                found = true;
            }

            if (!found)
            {
                spdlog::warn("Workspace::AllFiles - Symbol '{}' (path: '{}') in path index but not in type maps", name, path);
                not_found_count++;
            }
        }

        if (not_found_count > 0)
        {
            spdlog::warn("Workspace::AllFiles - Data inconsistency: {} symbols not found in type maps", not_found_count);
        }

        spdlog::debug("Workspace::AllFiles - Returning {} files", result.size());
        return result;
    }

}
