#pragma once

#include <memory>
#include <unordered_map>
#include <typeindex>
#include <functional>

/**
 * @brief Simple dependency injection container
 * 
 * Provides service registration and resolution for dependency injection.
 * Supports both singleton and factory-based service creation.
 */
class ServiceContainer {
public:
    ServiceContainer() = default;
    ~ServiceContainer() = default;

    /**
     * @brief Register a singleton service instance
     * @tparam TInterface Interface type
     * @tparam TImplementation Implementation type
     * @param instance Shared pointer to the service instance
     */
    template<typename TInterface, typename TImplementation>
    void registerSingleton(std::shared_ptr<TImplementation> instance) {
        static_assert(std::is_base_of_v<TInterface, TImplementation>, 
                      "TImplementation must inherit from TInterface");
        
        m_singletons[std::type_index(typeid(TInterface))] = instance;
    }

    /**
     * @brief Register a factory function for service creation
     * @tparam TInterface Interface type
     * @param factory Factory function that creates the service
     */
    template<typename TInterface>
    void registerFactory(std::function<std::shared_ptr<TInterface>()> factory) {
        m_factories[std::type_index(typeid(TInterface))] = [factory]() -> std::shared_ptr<void> {
            return std::static_pointer_cast<void>(factory());
        };
    }

    /**
     * @brief Resolve a service by its interface type
     * @tparam TInterface Interface type to resolve
     * @return Shared pointer to the service instance, nullptr if not found
     */
    template<typename TInterface>
    std::shared_ptr<TInterface> resolve() {
        std::type_index typeIndex(typeid(TInterface));
        
        // Check singletons first
        auto singletonIt = m_singletons.find(typeIndex);
        if (singletonIt != m_singletons.end()) {
            return std::static_pointer_cast<TInterface>(singletonIt->second);
        }
        
        // Check factories
        auto factoryIt = m_factories.find(typeIndex);
        if (factoryIt != m_factories.end()) {
            auto instance = factoryIt->second();
            return std::static_pointer_cast<TInterface>(instance);
        }
        
        return nullptr;
    }

    /**
     * @brief Check if a service is registered
     * @tparam TInterface Interface type to check
     * @return true if service is registered, false otherwise
     */
    template<typename TInterface>
    bool isRegistered() const {
        std::type_index typeIndex(typeid(TInterface));
        return m_singletons.find(typeIndex) != m_singletons.end() ||
               m_factories.find(typeIndex) != m_factories.end();
    }

    /**
     * @brief Clear all registered services
     */
    void clear() {
        m_singletons.clear();
        m_factories.clear();
    }

private:
    std::unordered_map<std::type_index, std::shared_ptr<void>> m_singletons;
    std::unordered_map<std::type_index, std::function<std::shared_ptr<void>()>> m_factories;
};
