#pragma once

#include <vector>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

namespace warfactory {

// Forward declarations
struct ResourcePatch;
struct WorldFeature;
enum class RegionalInfluence;
enum class BiomeType;
enum class ExplorationLevel;
class GMap;

/**
 * @brief Optimized tile data structure - 24 bytes per tile
 *
 * Compact structure with terrain data and feature set references.
 * Geological simulation ready with extended ranges for planetary formation.
 * Features accessed via feature_set_id in global map for memory efficiency.
 */
struct WorldTileData {
    // ========================================
    // TERRAIN DATA (11 bytes) - Always accessed, geological simulation ready
    // ========================================
    uint16_t terrain_type_id;       // Terrain type (65k possible types)
    uint16_t biome_type_id;         // Biome classification
    uint16_t elevation;             // Elevation: 0-65535 = -11km to +32km (geological range)
    int16_t temperature;            // Temperature: -32768 to +32767 = -3276°C to +3276°C (0.1°C increments)
    uint8_t humidity;               // Humidity: 0-255 = 0-100% (0.4% increments)
    uint8_t wind_data;              // Wind: 4 bits direction (0-15) + 4 bits intensity (0-15)
    uint8_t water_level;            // Accumulated water level (0-255, for river formation)

    // ========================================
    // METADATA (21 bytes) - Generation and gameplay
    // ========================================
    int8_t target_budget_score;     // Target budget score: -10 to +10
    uint32_t regional_influence_id; // → RegionalInfluenceData in global map
    uint8_t influence_strength;     // Regional influence strength: 0-255
    uint32_t tile_flags;            // Tile properties: PASSABLE, EXPLORED, etc.
    uint32_t feature_set_id;        // → FeatureSet in global map (0 = no features)
    uint8_t padding2[7];            // Align structure to 32 bytes (11 + 14 + 7 = 32)

    /**
     * @brief Constructor with default values
     */
    WorldTileData();

    /**
     * @brief Convert tile data to JSON
     */
    json toJson() const;

    /**
     * @brief Load tile data from JSON
     */
    void fromJson(const json& data);

    // ========================================
    // TERRAIN VALUE CONVERSION HELPERS
    // ========================================

    /**
     * @brief Convert elevation to meters (geological range: -11km to +32km)
     */
    float getElevationMeters() const { return (elevation - 11000.0f) / 1.524f; }

    /**
     * @brief Set elevation from meters
     */
    void setElevationMeters(float meters) {
        elevation = static_cast<uint16_t>(std::clamp((meters + 11000.0f) * 1.524f, 0.0f, 65535.0f));
    }

    /**
     * @brief Convert temperature to Celsius (0.1°C precision, range: -3276°C to +3276°C)
     */
    float getTemperatureCelsius() const { return temperature * 0.1f; }

    /**
     * @brief Set temperature from Celsius
     */
    void setTemperatureCelsius(float celsius) {
        temperature = static_cast<int16_t>(std::clamp(celsius * 10.0f, -32768.0f, 32767.0f));
    }

    /**
     * @brief Convert humidity to percentage (0.0-1.0)
     */
    float getHumidityPercent() const { return humidity / 255.0f; }

    /**
     * @brief Set humidity from percentage (0.0-1.0)
     */
    void setHumidityPercent(float percent) { humidity = static_cast<uint8_t>(std::clamp(percent * 255.0f, 0.0f, 255.0f)); }

    /**
     * @brief Get wind direction (0-15, where 0=North, 4=East, 8=South, 12=West)
     */
    uint8_t getWindDirection() const { return (wind_data >> 4) & 0x0F; }

    /**
     * @brief Set wind direction (0-15)
     */
    void setWindDirection(uint8_t direction) {
        wind_data = (wind_data & 0x0F) | ((direction & 0x0F) << 4);
    }

    /**
     * @brief Get wind intensity (0-15, where 0=calm, 15=hurricane)
     */
    uint8_t getWindIntensity() const { return wind_data & 0x0F; }

    /**
     * @brief Set wind intensity (0-15)
     */
    void setWindIntensity(uint8_t intensity) {
        wind_data = (wind_data & 0xF0) | (intensity & 0x0F);
    }

    /**
     * @brief Get wind vector in X,Y components (normalized -1.0 to 1.0)
     */
    std::pair<float, float> getWindVector() const {
        uint8_t direction = getWindDirection();
        float intensity = getWindIntensity() / 15.0f;
        float angle = direction * (2.0f * 3.14159f / 16.0f); // 16 directions
        return {intensity * sin(angle), intensity * cos(angle)}; // X=East, Y=North
    }

    /**
     * @brief Set wind from vector components
     */
    void setWindVector(float wind_x, float wind_y) {
        float intensity = sqrt(wind_x * wind_x + wind_y * wind_y);
        float angle = atan2(wind_x, wind_y); // X=East, Y=North
        if (angle < 0) angle += 2.0f * 3.14159f;

        uint8_t direction = static_cast<uint8_t>((angle * 16.0f) / (2.0f * 3.14159f)) % 16;
        uint8_t intensity_value = static_cast<uint8_t>(std::clamp(intensity * 15.0f, 0.0f, 15.0f));

        setWindDirection(direction);
        setWindIntensity(intensity_value);
    }

    /**
     * @brief Get accumulated water level (0-255, for hydrological simulation)
     */
    uint8_t getWaterLevel() const { return water_level; }

    /**
     * @brief Set accumulated water level (0-255)
     */
    void setWaterLevel(uint8_t level) { water_level = level; }

    /**
     * @brief Add water to current level (with overflow protection)
     */
    void addWater(uint8_t amount) {
        uint16_t new_level = static_cast<uint16_t>(water_level) + amount;
        water_level = static_cast<uint8_t>(std::min(new_level, 255u));
    }

    /**
     * @brief Remove water from current level (with underflow protection)
     */
    void removeWater(uint8_t amount) {
        if (water_level >= amount) {
            water_level -= amount;
        } else {
            water_level = 0;
        }
    }

    /**
     * @brief Get effective water surface elevation (elevation + water_level)
     */
    float getWaterSurfaceElevation() const {
        return getElevationMeters() + (water_level * 10.0f); // 10m per water level unit
    }
};

/**
 * @brief Lightweight tile wrapper with simple interface for world generation
 *
 * Provides easy access to tile data through GMap delegation. Acts as a smart wrapper
 * around tile index with simple methods for terrain, features, and gameplay data.
 */
class WorldTile {
private:
    uint32_t tile_index;        // Linear index in GMap (y * width + x)
    GMap* parent_map;           // Reference to parent map for data access

public:
    /**
     * @brief Constructor - creates lightweight wrapper
     * @param index Linear tile index in parent map
     * @param map Parent GMap reference
     */
    WorldTile(uint32_t index, GMap* map);

    /**
     * @brief Default constructor - invalid tile
     */
    WorldTile();

    /**
     * @brief Check if tile is valid
     */
    bool isValid() const { return parent_map != nullptr; }

    /**
     * @brief Get tile coordinates
     */
    std::pair<int, int> getCoordinates() const;

    /**
     * @brief Get tile index
     */
    uint32_t getIndex() const { return tile_index; }

    // ========================================
    // BASIC TERRAIN ACCESS - Delegate to GMap
    // ========================================

    // Terrain type and biome
    uint16_t getTerrainTypeId() const;
    uint16_t getBiomeTypeId() const;
    void setTerrainTypeId(uint16_t type_id);
    void setBiomeTypeId(uint16_t biome_id);

    // Elevation (in meters, auto-converted from uint8_t)
    float getElevation() const;
    void setElevation(float elevation_meters);

    // Temperature (in Celsius, auto-converted from uint8_t)
    float getTemperature() const;
    void setTemperature(float temperature_celsius);

    // Humidity (0.0-1.0, auto-converted from uint8_t)
    float getHumidity() const;
    void setHumidity(float humidity_percent);

    // Wind data (direction 0-15, intensity 0-15)
    uint8_t getWindDirection() const;
    void setWindDirection(uint8_t direction);
    uint8_t getWindIntensity() const;
    void setWindIntensity(uint8_t intensity);
    std::pair<float, float> getWindVector() const;
    void setWindVector(float wind_x, float wind_y);

    // Water level (0-255, for hydrological simulation)
    uint8_t getWaterLevel() const;
    void setWaterLevel(uint8_t level);
    void addWater(uint8_t amount);
    void removeWater(uint8_t amount);
    float getWaterSurfaceElevation() const;

    // ========================================
    // REGIONAL INFLUENCE - Via global maps
    // ========================================

    uint32_t getRegionalInfluenceId() const;
    void setRegionalInfluenceId(uint32_t influence_id);
    uint8_t getInfluenceStrength() const;
    void setInfluenceStrength(uint8_t strength);
    float getFeatureProbabilityModifier(const std::string& feature_type) const;

    // ========================================
    // BUDGET SYSTEM - Simple scoring
    // ========================================

    int8_t getTargetBudgetScore() const;
    void setTargetBudgetScore(int8_t target_score);
    float calculateActualBudgetScore() const;
    bool isBudgetBalanced(int8_t tolerance = 1) const;

    // ========================================
    // FEATURE MANAGEMENT - Via feature sets
    // ========================================

    uint32_t getFeatureSetId() const;
    void setFeatureSetId(uint32_t feature_set_id);
    std::vector<uint32_t> getFeatureIds() const;
    bool hasFeature(uint32_t feature_id) const;
    size_t getFeatureCount() const;

    // Feature compatibility for generation
    bool canAcceptFeatureType(const std::string& feature_type) const;
    bool canAcceptFeatureSet(uint32_t feature_set_id) const;

    // ========================================
    // RESOURCE MANAGEMENT - Via features integration
    // ========================================

    // Resources are integrated into features (as per analysis)
    uint64_t getTotalResourceQuantity(uint16_t resource_type_id) const;
    bool providesResource(uint16_t resource_type_id) const;
    std::vector<uint16_t> getAvailableResourceTypes() const;

    // ========================================
    // TERRAIN COMPATIBILITY - Generation helpers
    // ========================================

    bool isTerrainCompatible(const std::string& feature_type) const;
    bool isBiomeCompatible(const std::string& feature_type) const;
    bool isElevationCompatible(const std::string& feature_type) const;
    float getTraversability() const;
    bool isPassable() const;

    // ========================================
    // TILE FLAGS - State management
    // ========================================

    void setFlag(uint32_t flag, bool value);
    bool getFlag(uint32_t flag) const;
    uint32_t getFlags() const;

    // ========================================
    // DISCOVERY SYSTEM - Layered visibility
    // ========================================

    json getVisibleProperties() const;
    json getDiscoverableProperties(ExplorationLevel level) const;
    json getHiddenProperties() const;

    // ========================================
    // SERIALIZATION & UTILITIES
    // ========================================

    json toJson() const;
    void fromJson(const json& json_data);
    json exportForNetwork() const;
};

/**
 * @brief Tile flag constants
 */
namespace TileFlags {
    const uint32_t PASSABLE = 1 << 0;          // Tile allows movement
    const uint32_t DESTRUCTIBLE = 1 << 1;      // Features can be destroyed
    const uint32_t EXPLORED = 1 << 2;          // Tile has been explored
    const uint32_t GEOLOGICALLY_SURVEYED = 1 << 3;  // Geological exploration done
    const uint32_t MAGNETOMETRICALLY_SURVEYED = 1 << 4; // Magnetic exploration done
    const uint32_t CBRN_SURVEYED = 1 << 5;     // CBRN exploration done
    const uint32_t CONTAMINATED = 1 << 6;      // Tile has contamination
    const uint32_t STRATEGIC_VALUE = 1 << 7;   // Tile has strategic importance
    const uint32_t WATER_PRESENT = 1 << 8;     // Tile has water features
    const uint32_t RESOURCE_RICH = 1 << 9;     // Tile has significant resources
    const uint32_t FEATURE_RICH = 1 << 10;     // Tile has multiple features
    const uint32_t BUDGET_BALANCED = 1 << 11;  // Budget score is balanced
    const uint32_t REQUIRES_SPECIAL_EQUIPMENT = 1 << 12; // Special vehicles needed
    const uint32_t HISTORICALLY_SIGNIFICANT = 1 << 13;   // Cultural/historical value
    const uint32_t ENVIRONMENTALLY_PROTECTED = 1 << 14;  // Protected area
    const uint32_t MILITARILY_CONTROLLED = 1 << 15;      // Under military control
}

/**
 * @brief Exploration level requirements
 */
enum class ExplorationLevel {
    VISUAL = 0,           // Standard reconnaissance (visible features)
    GEOLOGICAL = 1,       // Geological vehicle required
    MAGNETOMETRIC = 2,    // Magnetometric vehicle required
    CBRN = 3,            // CBRN vehicle required
    MAXIMUM = 4          // All exploration completed
};

} // namespace warfactory