#pragma once

#include "block.h"

#include <array>
#include <cstdint>
#include <unordered_map>

struct ChunkPos {
    int x{};
    int y{};
    int z{};

    bool operator==(const ChunkPos& other) const = default;
};

struct MicroVoxelGrid {
    static constexpr int SIZE = 16;
    static constexpr int COUNT = SIZE * SIZE * SIZE;

    std::array<BlockType, COUNT> voxels{};

    MicroVoxelGrid() {
        voxels.fill(BlockType::Air);
    }

    static int index(int x, int y, int z) {
        return x + y * SIZE + z * SIZE * SIZE;
    }

    BlockType get(int x, int y, int z) const {
        return voxels[index(x, y, z)];
    }

    void set(int x, int y, int z, BlockType type) {
        voxels[index(x, y, z)] = type;
    }
};

class Chunk {
public:
    static constexpr int SIZE = 16;
    static constexpr std::uint8_t MAX_WATER_LEVEL = 16;

    explicit Chunk(ChunkPos pos);

    const ChunkPos& position() const;

    BlockType get(int x, int y, int z) const;
    void set(int x, int y, int z, BlockType type);

    bool hasWater(int x, int y, int z) const;
    std::uint8_t getWaterLevel(int x, int y, int z) const;
    void setWaterLevel(int x, int y, int z, std::uint8_t level);
    void removeWater(int x, int y, int z);

    bool isSubdivided(int x, int y, int z) const;
    BlockType getMicroBlock(int x, int y, int z, int mx, int my, int mz) const;
    void setMicroBlock(int x, int y, int z, int mx, int my, int mz, BlockType type);
    void subdivideBlock(int x, int y, int z);
    void clearSubdivision(int x, int y, int z);

    static int index(int x, int y, int z);

    // Player-placed leaves tracking (these blocks should not decay when tree is broken)
    bool isLeafPlayerPlaced(int x, int y, int z) const;
    void markLeafPlayerPlaced(int x, int y, int z);
    void clearLeafPlayerPlaced(int x, int y, int z);
    const std::unordered_map<int, bool>& playerPlacedLeaves() const { return playerPlacedLeaves_; }

private:
    void validateBlockCoords(int x, int y, int z, const char* fn) const;
    void validateMicroCoords(int mx, int my, int mz, const char* fn) const;
    MicroVoxelGrid& ensureSubdivisionFromBlock(int x, int y, int z);
    void cleanupSubdivisionState(int x, int y, int z);

    ChunkPos position_{};
    std::array<BlockType, SIZE * SIZE * SIZE> blocks_{};
    std::unordered_map<int, std::uint8_t> waterLevels_{};
    std::unordered_map<int, MicroVoxelGrid> microVoxels_{};
    std::unordered_map<int, bool> playerPlacedLeaves_{}; // blocks placed by player (won't decay)
};
