#pragma once

#include "WorldFeature.h"
#include "FeatureSet.h"
#include "GMap.h"
#include <nlohmann/json.hpp>
#include <string>
#include <unordered_map>

using json = nlohmann::json;

namespace warfactory {

/**
 * @brief Helper for generation algorithms - handles feature placement complexity
 *
 * Provides simple interface for generation algorithms while hiding all internal
 * complexity of feature placement, feature set management, budget calculations,
 * and resource integration. Does NOT do generation itself - just helps algorithms.
 */
class FeatureManager {
private:
    GMap* world_map;                                    // Reference to world map (not owned)

    // Configuration cache (loaded once, used repeatedly)
    std::unordered_map<std::string, json> feature_type_configs;     // Feature definitions
    std::unordered_map<std::string, float> base_budget_scores;      // Type -> budget score

    // Feature set optimization cache
    std::unordered_map<std::vector<uint32_t>, uint32_t> feature_set_cache;  // Deduplication

    // ========================================
    // INTERNAL COMPLEXITY - Hidden from users
    // ========================================

    /**
     * @brief Create WorldFeature from type and position (internal)
     */
    WorldFeature createFeatureInstance(const std::string& feature_type, int center_x, int center_y) const;

    /**
     * @brief Update affected tiles with new feature set (internal)
     */
    void updateAffectedTiles(const WorldFeature& feature);

    /**
     * @brief Calculate budget impact without placing (internal)
     */
    float calculateBudgetImpact(const std::string& feature_type, int x, int y) const;

    /**
     * @brief Check terrain/biome/elevation compatibility (internal)
     */
    bool checkTerrainCompatibility(const std::string& feature_type, int x, int y) const;

    /**
     * @brief Generate integrated resources for feature (internal)
     */
    void generateIntegratedResources(WorldFeature& feature) const;

public:
    /**
     * @brief Constructor
     */
    FeatureManager();

    /**
     * @brief Destructor
     */
    ~FeatureManager() = default;

    // ========================================
    // INITIALIZATION - Simple setup
    // ========================================

    /**
     * @brief Set reference to world map
     * @param map Mutable reference to world map
     */
    void setWorldMap(GMap* map);

    /**
     * @brief Load feature definitions (call once)
     * @param feature_configs JSON configuration for all feature types
     */
    void loadFeatureDefinitions(const json& feature_configs);

    // ========================================
    // CORE INTERFACE - Helper for generation algorithms
    // ========================================

    /**
     * @brief Check if feature can be placed at location
     * @param feature_type Feature type name (e.g., "terikon", "scrap_metal")
     * @param x X coordinate
     * @param y Y coordinate
     * @return true if feature can be placed (terrain compatible, space available, etc.)
     */
    bool canPlaceFeature(const std::string& feature_type, int x, int y) const;

    /**
     * @brief Place single feature at coordinates (handles all complexity)
     * @param feature_type Feature type name
     * @param center_x Center X coordinate
     * @param center_y Center Y coordinate
     * @return Feature ID if placed successfully, 0 if failed
     *
     * Internally handles:
     * - Creating WorldFeature with resources
     * - Finding affected tiles
     * - Creating/updating FeatureSets
     * - Updating tile feature_set_ids
     * - Budget score recalculation
     */
    uint32_t placeFeature(const std::string& feature_type, int center_x, int center_y);

    /**
     * @brief Remove feature from map (handles cleanup)
     * @param feature_id Feature ID to remove
     * @return true if feature was removed successfully
     *
     * Internally handles:
     * - Removing from GMap::features
     * - Updating affected tiles
     * - Cleaning up unused FeatureSets
     * - Budget score recalculation
     */
    bool removeFeature(uint32_t feature_id);

    // ========================================
    // UTILITY QUERIES - For algorithm decision making
    // ========================================

    /**
     * @brief Get budget impact of placing feature (without placing)
     * @param feature_type Feature type name
     * @param x X coordinate
     * @param y Y coordinate
     * @return Budget score impact (positive/negative)
     */
    float getBudgetImpact(const std::string& feature_type, int x, int y) const;

    /**
     * @brief Check if feature type exists in configuration
     * @param feature_type Feature type name
     * @return true if feature type is defined
     */
    bool isFeatureTypeValid(const std::string& feature_type) const;

    /**
     * @brief Get feature at specific coordinates
     * @param x X coordinate
     * @param y Y coordinate
     * @return Vector of feature IDs at location
     */
    std::vector<uint32_t> getFeaturesAt(int x, int y) const;

    /**
     * @brief Check if location has any features
     * @param x X coordinate
     * @param y Y coordinate
     * @return true if tile has features
     */
    bool hasFeatures(int x, int y) const;

    /**
     * @brief Get number of features at location
     * @param x X coordinate
     * @param y Y coordinate
     * @return Feature count at tile
     */
    size_t getFeatureCount(int x, int y) const;

    // ========================================
    // CONFIGURATION QUERIES - For algorithm parameters
    // ========================================

    /**
     * @brief Get base budget score for feature type
     * @param feature_type Feature type name
     * @return Base budget score (-10 to +10)
     */
    float getBaseBudgetScore(const std::string& feature_type) const;

    /**
     * @brief Get feature category for type
     * @param feature_type Feature type name
     * @return Feature category
     */
    FeatureCategory getFeatureCategory(const std::string& feature_type) const;

    /**
     * @brief Get available feature types for category
     * @param category Feature category
     * @return Vector of feature type names
     */
    std::vector<std::string> getFeatureTypesForCategory(FeatureCategory category) const;

    // ========================================
    // OPTIMIZATION AND MAINTENANCE
    // ========================================

    /**
     * @brief Optimize feature set storage (remove unused sets)
     * @return Number of feature sets cleaned up
     */
    int optimizeFeatureSets();

    /**
     * @brief Get statistics for debugging/monitoring
     * @return JSON with feature counts, memory usage, etc.
     */
    json getStats() const;

    /**
     * @brief Validate all features and sets consistency
     * @return JSON with validation results
     */
    json validateConsistency() const;

    // ========================================
    // FEATURE SET MANAGEMENT - Advanced helpers
    // ========================================

    /**
     * @brief Place multiple features as coordinated set
     * @param feature_types Vector of feature type names
     * @param center_x Center X coordinate
     * @param center_y Center Y coordinate
     * @return Feature set ID if placed successfully, 0 if failed
     */
    uint32_t placeFeatureGroup(const std::vector<std::string>& feature_types, int center_x, int center_y);

    /**
     * @brief Check if feature group can be placed
     * @param feature_types Vector of feature type names
     * @param center_x Center X coordinate
     * @param center_y Center Y coordinate
     * @return true if all features in group can be placed
     */
    bool canPlaceFeatureGroup(const std::vector<std::string>& feature_types, int center_x, int center_y) const;
};

} // namespace warfactory