#pragma once

#include <cstdint>

namespace block {

    // For internal use only. These are examples, we will probably need
    // a different way of assigning IDs in the future but a list should
    // be fine for now, I guess.
    // I don’t know how Minecraft assigns its IDs or if it even matters
    // given that it has used string IDs for a while now. We just need an
    // internal way to distinguish between classes.
    namespace ids {
        const uint16_t AIR = 0;
        const uint16_t STONE = 1;
    }

    // These are intended to be combined using bitwise OR.
    namespace collisionBehavior {
        // Let the block handle it.
        // A function on the relevant block class will deal with it.
        const uint8_t UNKNOWN = 0b00000000;

        // Collision box inhibits movement?
        // (stone or stone slab)
        const uint8_t SOLID = 0b00000001;

        // Does collision box fill entire block?
        // (stone or grass block)
        //
        // The shape of the collision box is part of the relevant block class
        // when this bit is unset.
        const uint8_t FULL_BLOCK = 0b00000010;

        const uint8_t SOLID_FULL_BLOCK = SOLID | FULL_BLOCK;

        // Slow down entities when inside the block?
        // (vines or soulsand)
        //
        // Entities are considered to be inside a given block when rounding
        // their coordinates results in the coordinates of the block.
        //
        // The amount of slowdown is controlled by a function on the relevant
        // block class.
        const uint8_t SLOWDOWN = 0b00000100;

        // Slow down entities when touching the collision box of the block?
        // (honey block)
        //
        // The amount of slowdown is controlled by a function on the relevant
        // block class.
        const uint8_t SURFACE_SLOWDOWN = 0b00001000;

        // Deal damage when entities are inside it?
        // (berry bush)
        //
        // Entities are considered to be inside a given block when rounding
        // their coordinates results in the coordinates of the block.
        //
        // The amount of damage is controlled by a function on the relevant
        // block class.
        const uint8_t DAMAGE = 0b00010000;

        // Deal damage when entities touch the collision box?
        // (magma block)
        //
        // The amount of damage is controlled by a function on the relevant
        // block class.
        const uint8_t SURFACE_DAMAGE = 0b00010000;

        // Is the block bouncy?
        // (bed or slime block)
        //
        // The bounciness of the block is handled by the relevant block class.
        const uint8_t BOUNCY = 0b00100000;
    }

    class Generic {
        private:
        public:
            virtual uint16_t id() = 0;
            virtual uint8_t collisionBehavior() = 0;

            //TODO: (not pure) virtual functions for collision box, slowdown, damage, bounciness, etc.

            //TODO: (not pure) virtual function for hitbox (defaults to full block)
    }

    class Air {
        public:
            uint16_t id() {
                return ids::AIR;
            }
            uint8_t collisionBehavior() {
                // is a full block but doesn't collide or anything else
                return collisionBehavior::FULL_BLOCK;
            }
    }

    BlockGeneric* getNewBlockFromID(uint16_t id) {
        //TODO
    }
}
