#pragma once

#include <cstdint>
#include <algorithm>
#include <cmath>

namespace warfactory {

struct GTile {
    // ========================================
    // CORE DATA (16 bytes total) - Complete tile data
    // ========================================
    uint16_t elevation;         // Elevation: 0-65535 = -32km to +32km (geological range)
    int16_t temperature;        // Temperature: -32768 to +32767 = -3276°C to +3276°C (0.1°C increments)
    uint16_t biome_type_id;     // Biome classification
    uint8_t water_token;        // Water/rain tokens from climate simulation
    uint8_t wind_token;         // Wind tokens from climate simulation
    int8_t target_budget_score; // Target budget score: -10 to +10
    uint16_t destruction_token; // Bits 1-4: highWind, 5-8: flood, 9-12: hurricane, 13-16: reserved
    uint16_t flags;             // Tile properties and state flags
    uint32_t feature_set_id;    // Features present on this tile (0 = no features)

    /**
     * @brief Constructor with default values
     */
    GTile() : elevation(0), temperature(-1000), biome_type_id(0), water_token(0), wind_token(0),
              target_budget_score(0), destruction_token(0), flags(0), feature_set_id(0) {}

    // ========================================
    // ELEVATION CONVERSION (same as WorldTileData)
    // ========================================

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

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

    // ========================================
    // TEMPERATURE CONVERSION (same as WorldTileData)
    // ========================================

    /**
     * @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));
    }

    // ========================================
    // BIOME & CLIMATE DATA
    // ========================================

    /**
     * @brief Get biome type ID
     */
    uint16_t getBiomeTypeId() const { return biome_type_id; }

    /**
     * @brief Set biome type ID
     */
    void setBiomeTypeId(uint16_t biome_id) { biome_type_id = biome_id; }

    /**
     * @brief Get water tokens from climate simulation
     */
    uint8_t getWaterToken() const { return water_token; }

    /**
     * @brief Set water tokens
     */
    void setWaterToken(uint8_t tokens) { water_token = tokens; }

    /**
     * @brief Add water tokens
     */
    void addWaterToken(uint8_t additional_tokens) {
        uint16_t new_total = static_cast<uint16_t>(water_token) + additional_tokens;
        water_token = static_cast<uint8_t>(std::min(new_total, static_cast<uint16_t>(255)));
    }

    /**
     * @brief Get wind tokens from climate simulation
     */
    uint8_t getWindToken() const { return wind_token; }

    /**
     * @brief Set wind tokens
     */
    void setWindToken(uint8_t tokens) { wind_token = tokens; }

    /**
     * @brief Add wind tokens
     */
    void addWindToken(uint8_t additional_tokens) {
        uint16_t new_total = static_cast<uint16_t>(wind_token) + additional_tokens;
        wind_token = static_cast<uint8_t>(std::min(new_total, static_cast<uint16_t>(255)));
    }

    // ========================================
    // DESTRUCTION TOKEN (packed in 16 bits)
    // ========================================

    /**
     * @brief Get high wind token (bits 1-4)
     */
    uint8_t getHighWindToken() const {
        return destruction_token & 0x0F;
    }

    /**
     * @brief Set high wind token (0-15)
     */
    void setHighWindToken(uint8_t tokens) {
        destruction_token = (destruction_token & 0xFFF0) | (tokens & 0x0F);
    }

    /**
     * @brief Get flood token (bits 5-8)
     */
    uint8_t getFloodToken() const {
        return (destruction_token >> 4) & 0x0F;
    }

    /**
     * @brief Set flood token (0-15)
     */
    void setFloodToken(uint8_t tokens) {
        destruction_token = (destruction_token & 0xFF0F) | ((tokens & 0x0F) << 4);
    }

    /**
     * @brief Get hurricane token (bits 9-12)
     */
    uint8_t getHurricaneToken() const {
        return (destruction_token >> 8) & 0x0F;
    }

    /**
     * @brief Set hurricane token (0-15)
     */
    void setHurricaneToken(uint8_t tokens) {
        destruction_token = (destruction_token & 0xF0FF) | ((tokens & 0x0F) << 8);
    }

    /**
     * @brief Add high wind tokens
     */
    void addHighWindToken(uint8_t additional) {
        uint8_t current = getHighWindToken();
        setHighWindToken(std::min(static_cast<uint8_t>(current + additional), static_cast<uint8_t>(15)));
    }

    /**
     * @brief Add flood tokens
     */
    void addFloodToken(uint8_t additional) {
        uint8_t current = getFloodToken();
        setFloodToken(std::min(static_cast<uint8_t>(current + additional), static_cast<uint8_t>(15)));
    }

    /**
     * @brief Add hurricane tokens
     */
    void addHurricaneToken(uint8_t additional) {
        uint8_t current = getHurricaneToken();
        setHurricaneToken(std::min(static_cast<uint8_t>(current + additional), static_cast<uint8_t>(15)));
    }

    // ========================================
    // BUDGET SYSTEM
    // ========================================

    /**
     * @brief Get target budget score (-10 to +10)
     */
    int8_t getTargetBudgetScore() const { return target_budget_score; }

    /**
     * @brief Set target budget score
     */
    void setTargetBudgetScore(int8_t score) { target_budget_score = score; }

    // ========================================
    // FLAGS & FEATURES
    // ========================================

    /**
     * @brief Get tile flags
     */
    uint16_t getFlags() const { return flags; }

    /**
     * @brief Set specific flag
     */
    void setFlag(uint16_t flag, bool value) {
        if (value) {
            flags |= flag;
        } else {
            flags &= ~flag;
        }
    }

    /**
     * @brief Check if flag is set
     */
    bool hasFlag(uint16_t flag) const { return (flags & flag) != 0; }

    /**
     * @brief Get feature set ID
     */
    uint32_t getFeatureSetId() const { return feature_set_id; }

    /**
     * @brief Set feature set ID
     */
    void setFeatureSetId(uint32_t feature_id) { feature_set_id = feature_id; }

    /**
     * @brief Check if tile has features
     */
    bool hasFeatures() const { return feature_set_id != 0; }

    // ========================================
    // PHASE 1 OPERATIONS
    // ========================================

    /**
     * @brief Apply heat from meteorite impact
     */
    void applyImpactHeat(float heat_celsius) {
        float current_temp = getTemperatureCelsius();
        setTemperatureCelsius(current_temp + heat_celsius);
    }

    /**
     * @brief Cool tile by given amount
     */
    void coolTile(float cooling_celsius) {
        float current_temp = getTemperatureCelsius();
        setTemperatureCelsius(current_temp - cooling_celsius);
    }
};

} // namespace warfactory