#pragma once

#include "WorldTile.h"
#include <vector>
#include <string>
#include <unordered_map>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

namespace warfactory {

// Forward declarations
struct WorldFeature;

/**
 * @brief Global world map data structure with budget system and regional influences
 *
 * Implements the revolutionary budget-based generation system from analysis:
 * - Automatic risk/reward balancing through -10 to +10 scoring
 * - Regional influences that create specialized geographical zones
 * - Separation of terrain (always loaded) and resources (on-demand)
 * - Support for 218+ feature types with budget integration
 * - Integration with WorldTile class for encapsulated tile logic
 */
class GMap {
private:
    int width, height;
    uint64_t world_seed;                    // Global generation seed

    // ========================================
    // TILE DATA - Optimized 24-byte structure
    // ========================================
    std::vector<WorldTileData> tiles;  // Linear array: index = y * width + x

    // ========================================
    // GLOBAL MAPS - Referenced by tiles
    // ========================================

    // Feature sets - collections of features for tiles
    std::unordered_map<uint32_t, std::vector<uint32_t>> feature_sets;  // set_id -> feature_ids
    uint32_t next_feature_set_id;

    // Individual features - referenced by feature sets
    std::unordered_map<uint32_t, WorldFeature> features;
    uint32_t next_feature_id;

    // Regional influences - complex influence data
    std::unordered_map<uint32_t, json> regional_influences;  // influence_id -> influence_data
    uint32_t next_regional_influence_id;

    // Feature type definitions (loaded from configuration)
    std::unordered_map<std::string, json> feature_definitions;

    // Budget scoring metadata
    std::unordered_map<int, int> budget_score_distribution; // Score -> tile count

    // ========================================
    // INTERNAL HELPERS - Data access optimization
    // ========================================

    /**
     * @brief Get tile index from coordinates
     */
    uint32_t getTileIndex(int x, int y) const { return y * width + x; }

    /**
     * @brief Get coordinates from tile index
     */
    std::pair<int, int> getCoordinatesFromIndex(uint32_t index) const {
        return {index % width, index / width};
    }

public:
    /**
     * @brief Construct world map with specified dimensions and seed
     * @param w Map width in tiles
     * @param h Map height in tiles
     * @param seed World generation seed for deterministic results
     */
    GMap(int w, int h, uint64_t seed = 0);

    /**
     * @brief Destructor - ensures proper cleanup
     */
    ~GMap();

    // ========================================
    // BASIC ACCESSORS
    // ========================================
    int getWidth() const { return width; }
    int getHeight() const { return height; }
    uint64_t getWorldSeed() const { return world_seed; }

    /**
     * @brief Get lightweight tile wrapper for easy access
     */
    WorldTile getTile(int x, int y);
    WorldTile getTile(int x, int y) const;

    /**
     * @brief Check if coordinates are valid
     */
    bool isValidCoordinate(int x, int y) const;

    // ========================================
    // DIRECT TILE DATA ACCESS - For WorldTile wrapper
    // ========================================

    // Direct access to tile data (used by WorldTile)
    WorldTileData& getTileData(uint32_t tile_index) { return tiles[tile_index]; }
    const WorldTileData& getTileData(uint32_t tile_index) const { return tiles[tile_index]; }

    // ========================================
    // FEATURE SET MANAGEMENT
    // ========================================

    /**
     * @brief Create new feature set
     * @param feature_ids Vector of feature IDs for this set
     * @return New feature set ID
     */
    uint32_t createFeatureSet(const std::vector<uint32_t>& feature_ids);

    /**
     * @brief Get feature IDs from feature set
     * @param set_id Feature set ID
     * @return Vector of feature IDs (empty if set doesn't exist)
     */
    std::vector<uint32_t> getFeatureSet(uint32_t set_id) const;

    /**
     * @brief Check if feature set exists
     */
    bool hasFeatureSet(uint32_t set_id) const;

    /**
     * @brief Get or create feature set for feature combination
     * @param feature_ids Vector of feature IDs
     * @return Feature set ID (existing or newly created)
     */
    uint32_t getOrCreateFeatureSet(const std::vector<uint32_t>& feature_ids);

    // ========================================
    // REGIONAL INFLUENCE MANAGEMENT
    // ========================================

    /**
     * @brief Create regional influence
     * @param influence_data JSON data describing the influence
     * @return New regional influence ID
     */
    uint32_t createRegionalInfluence(const json& influence_data);

    /**
     * @brief Get regional influence data
     * @param influence_id Regional influence ID
     * @return JSON influence data (null if doesn't exist)
     */
    json getRegionalInfluence(uint32_t influence_id) const;

    // ========================================
    // INITIALIZATION
    // ========================================

    /**
     * @brief Initialize tiles array (called by constructor)
     */
    void initializeTiles();

    // Budget system methods
    /**
     * @brief Set target budget score for a tile
     */
    void setTargetBudgetScore(int x, int y, float target_score);

    /**
     * @brief Calculate actual budget score for a tile (delegates to WorldTile)
     */
    float calculateActualBudgetScore(int x, int y) const;

    /**
     * @brief Update actual budget scores for all tiles
     */
    void updateAllBudgetScores();

    /**
     * @brief Get budget score distribution statistics
     */
    json getBudgetScoreDistribution() const;

    /**
     * @brief Balance budget for a specific tile
     */
    bool balanceTileBudget(int x, int y);

    /**
     * @brief Balance budgets for entire map
     */
    void balanceAllBudgets();

    // Regional influence methods
    /**
     * @brief Add regional influence zone
     */
    void addRegionalInfluence(RegionalInfluence influence, const std::vector<std::pair<int, int>>& area);

    /**
     * @brief Get regional influence at coordinates
     */
    RegionalInfluence getRegionalInfluence(int x, int y) const;

    /**
     * @brief Get feature probability modifier for location
     */
    float getFeatureProbabilityModifier(int x, int y, const std::string& feature_type) const;

    // Resource patch methods
    /**
     * @brief Add resource patch to the map
     */
    uint32_t addResourcePatch(const ResourcePatch& patch);

    /**
     * @brief Get resource patch by ID
     */
    const ResourcePatch* getResourcePatch(uint32_t patch_id) const;

    /**
     * @brief Get mutable resource patch by ID
     */
    ResourcePatch* getResourcePatchMutable(uint32_t patch_id);

    /**
     * @brief Get all resource patches affecting a tile
     */
    std::vector<const ResourcePatch*> getResourcePatchesAt(int x, int y) const;

    /**
     * @brief Remove resource patch
     */
    bool removeResourcePatch(uint32_t patch_id);

    /**
     * @brief Get all resource patches
     */
    const std::unordered_map<uint32_t, ResourcePatch>& getResourcePatches() const { return resource_patches; }

    // Feature management methods
    /**
     * @brief Add feature to the map
     */
    uint32_t addFeature(const WorldFeature& feature);

    /**
     * @brief Get feature by ID
     */
    const WorldFeature* getFeature(uint32_t feature_id) const;

    /**
     * @brief Get mutable feature by ID
     */
    WorldFeature* getFeatureMutable(uint32_t feature_id);

    /**
     * @brief Remove feature from map
     */
    bool removeFeature(uint32_t feature_id);

    /**
     * @brief Get all features
     */
    const std::unordered_map<uint32_t, WorldFeature>& getFeatures() const { return features; }

    /**
     * @brief Set feature type definitions
     */
    void setFeatureDefinitions(const std::unordered_map<std::string, json>& definitions);

    /**
     * @brief Get feature type definitions
     */
    const std::unordered_map<std::string, json>& getFeatureDefinitions() const { return feature_definitions; }

    // Serialization methods
    /**
     * @brief Export entire map to JSON
     */
    json toJson() const;

    /**
     * @brief Import map from JSON data
     */
    void fromJson(const json& data);

    /**
     * @brief Export region to JSON for networking/storage
     */
    json exportRegion(int start_x, int start_y, int region_width, int region_height) const;

    /**
     * @brief Import region from JSON (for streaming/networking)
     */
    void importRegion(const json& region_data, int start_x, int start_y);

    // Utility methods
    /**
     * @brief Clear all data and reset to default state
     */
    void clear();

    /**
     * @brief Generate deterministic tile seed for procedural generation
     */
    uint32_t getTileSeed(int x, int y) const;

    /**
     * @brief Validate map consistency
     */
    bool validate() const;

    /**
     * @brief Get memory usage statistics
     */
    json getMemoryStats() const;

    /**
     * @brief Optimize memory usage (remove unused patches, compact vectors)
     */
    void optimizeMemory();
};

} // namespace warfactory