#pragma once

namespace MayaFlux::Core {
class Window;
class VKImage;
}

namespace MayaFlux::Portal::Graphics {

//============================================================================
// Primitive Topology
//============================================================================

/**
 * @enum PrimitiveTopology
 * @brief Vertex assembly primitive topology
 *
 * Used to configure how vertices are assembled into primitives
 * before rasterization.
 */
enum class PrimitiveTopology : uint8_t {
    POINT_LIST,
    LINE_LIST,
    LINE_STRIP,
    TRIANGLE_LIST,
    TRIANGLE_STRIP,
    TRIANGLE_FAN
};

//============================================================================
// Rasterization
//============================================================================

/**
 * @enum PolygonMode
 * @brief Rasterization polygon mode
 */
enum class PolygonMode : uint8_t {
    FILL,
    LINE,
    POINT
};

/**
 * @enum CullMode
 * @brief Face culling mode
 */
enum class CullMode : uint8_t {
    NONE,
    FRONT,
    BACK,
    FRONT_AND_BACK
};

//============================================================================
// Depth/Stencil
//============================================================================

/**
 * @enum CompareOp
 * @brief Depth/stencil comparison operation
 */
enum class CompareOp : uint8_t {
    NEVER,
    LESS,
    EQUAL,
    LESS_OR_EQUAL,
    GREATER,
    NOT_EQUAL,
    GREATER_OR_EQUAL,
    ALWAYS
};

//============================================================================
// Blending
//============================================================================

/**
 * @enum BlendFactor
 * @brief Blending factor
 */
enum class BlendFactor : uint8_t {
    ZERO,
    ONE,
    SRC_COLOR,
    ONE_MINUS_SRC_COLOR,
    DST_COLOR,
    ONE_MINUS_DST_COLOR,
    SRC_ALPHA,
    ONE_MINUS_SRC_ALPHA,
    DST_ALPHA,
    ONE_MINUS_DST_ALPHA
};

/**
 * @enum BlendOp
 * @brief Blending operation
 */
enum class BlendOp : uint8_t {
    ADD,
    SUBTRACT,
    REVERSE_SUBTRACT,
    MIN,
    MAX
};

//============================================================================
// GPU Buffer Bindings
//============================================================================

/**
 * @enum BufferUsageHint
 * @brief Semantic usage hint for buffer allocation and memory properties
 *
 * This enum describes the intended usage pattern of a buffer, which informs
 * the graphics backend how to allocate memory and set Vulkan usage flags.
 * It is not a direct mapping to Vulkan flags, but rather a higher-level
 * abstraction for common use cases.
 */
enum class BufferUsageHint : uint8_t {
    STAGING, ///< Host-visible staging buffer (CPU-writable, eTransferSrc|Dst)
    DEVICE, ///< Device-local GPU-only buffer
    COMPUTE, ///< Storage buffer for compute shaders (device-local)
    VERTEX, ///< Vertex buffer
    INDEX, ///< Index buffer
    UNIFORM, ///< Uniform buffer (host-visible)
    UNIFORM_BDA, ///< Uniform buffer with device address query support
    STORAGE_BDA, ///< Storage buffer with device address query support
    INDIRECT, ///< Indirect draw/dispatch buffer (device-local)
    HOST_STORAGE, ///< Host-visible storage buffer (eStorageBuffer + eHostVisible|eHostCoherent)
    COMPUTE_STORAGE, ///< Bare eStorageBuffer, no transfer flags. GpuResourceManager's host-visible/host-coherent compute buffers.
};

/**
 * @struct GpuBufferBinding
 * @brief Declares a single storage buffer or image binding a compute shader expects.
 *
 * Vulkan-agnostic description consumed by ComputePress/ShaderFoundry to
 * derive descriptor types, barrier targets, and staging behavior. Carries
 * no vk:: types itself; translation to vk::DescriptorType happens at the
 * point of use.
 */
struct GpuBufferBinding {
    uint32_t set { 0 }; ///< Descriptor set index.
    uint32_t binding { 0 }; ///< Binding index within the set.
    bool skip_auto_readback { false }; ///< Skip automatic CPU readback after dispatch for this binding.

    /**
     * @enum Direction
     * @brief Data flow direction for this binding.
     *
     * INPUT_OUTPUT bindings receive a cross-pass memory barrier when used
     * across multiple recorded dispatches in one command buffer (see
     * ComputePress::record_sequence), since the same resource is both
     * read and written by consecutive stages.
     */
    enum class Direction : uint8_t {
        INPUT,
        OUTPUT,
        INPUT_OUTPUT
    } direction { Direction::INPUT };

    /**
     * @enum ElementType
     * @brief Element type the shader expects in this binding.
     *
     * FLOAT32          — cast double channels to float (default).
     * UINT32           — reinterpret variant bytes as uint32_t.
     * INT32            — reinterpret variant bytes as int32_t.
     * PASSTHROUGH      — upload raw variant bytes with no cast; caller
     *                    must pre-stage for INPUT / INPUT_OUTPUT bindings.
     * IMAGE_STORAGE    — writeonly/readonly image2D, storage image descriptor.
     * IMAGE_SAMPLED    — sampler2D, combined image sampler descriptor.
     */
    enum class ElementType : uint8_t {
        FLOAT32,
        UINT32,
        INT32,
        PASSTHROUGH,
        IMAGE_STORAGE,
        IMAGE_SAMPLED
    } element_type { ElementType::FLOAT32 };

    BufferUsageHint usage_hint { BufferUsageHint::COMPUTE_STORAGE }; ///< Hint for buffer allocation and memory properties.
};

/**
 * @brief Byte width of one GpuBufferBinding::ElementType element.
 *
 * Bridges to Kakshya::gpu_data_format_bytes for FLOAT32/UINT32/INT32,
 * the single authoritative sizing source. Returns 0 for PASSTHROUGH,
 * IMAGE_STORAGE, and IMAGE_SAMPLED, which carry no fixed element width.
 *
 * @param et ElementType to size.
 * @return Byte width, or 0 if unsized.
 */
[[nodiscard]] size_t element_type_bytes(GpuBufferBinding::ElementType et) noexcept;

//============================================================================
// Shader Types
//============================================================================

/**
 * @enum ShaderStage
 * @brief User-friendly shader stage enum
 *
 * Abstracts vk::ShaderStageFlagBits for Portal API convenience.
 * Maps directly to Vulkan stages internally.
 */
enum class ShaderStage : uint8_t {
    COMPUTE,
    VERTEX,
    FRAGMENT,
    GEOMETRY,
    TESS_CONTROL,
    TESS_EVALUATION,
    MESH,
    TASK
};

//============================================================================
// Image Helpers
//============================================================================

/**
 * @enum ImageFormat
 * @brief User-friendly image format enum
 *
 * Abstracts Vulkan formats for Portal API convenience.
 * Maps to vk::Format internally.
 */
enum class ImageFormat : uint8_t {
    // Normalized formats
    R8, ///< Single channel 8-bit
    RG8, ///< Two channel 8-bit
    RGB8, ///< Three channel 8-bit
    RGBA8, ///< Four channel 8-bit
    RGBA8_SRGB, ///< Four channel 8-bit sRGB

    BGRA8, ///< 8-bit BGRA unsigned normalized
    BGRA8_SRGB, ///< 8-bit BGRA sRGB

    // Floating point formats
    R16F, ///< Single channel 16-bit float
    RG16F, ///< Two channel 16-bit float
    RGBA16F, ///< Four channel 16-bit float
    R32F, ///< Single channel 32-bit float
    RG32F, ///< Two channel 32-bit float
    RGBA32F, ///< Four channel 32-bit float

    R16, ///< Single channel 16-bit unsigned integer
    RG16, ///< Two channel 16-bit unsigned integer
    RGBA16, ///< Four channel 16-bit unsigned integer

    // Depth/stencil formats
    DEPTH16, ///< 16-bit depth
    DEPTH24, ///< 24-bit depth
    DEPTH32F, ///< 32-bit float depth
    DEPTH24_STENCIL8 ///< 24-bit depth + 8-bit stencil
};

/**
 * @enum FilterMode
 * @brief Texture filtering mode
 */
enum class FilterMode : uint8_t {
    NEAREST, ///< Nearest neighbor (pixelated)
    LINEAR, ///< Bilinear filtering (smooth)
    CUBIC ///< Bicubic filtering (high quality, slower)
};

/**
 * @enum AddressMode
 * @brief Texture addressing mode (wrapping)
 */
enum class AddressMode : uint8_t {
    REPEAT, ///< Repeat texture
    MIRRORED_REPEAT, ///< Mirror and repeat
    CLAMP_TO_EDGE, ///< Clamp to edge color
    CLAMP_TO_BORDER ///< Clamp to border color
};

/**
 * @struct SamplerConfig
 * @brief Sampler configuration
 */
struct SamplerConfig {
    FilterMode mag_filter = FilterMode::LINEAR;
    FilterMode min_filter = FilterMode::LINEAR;
    AddressMode address_mode_u = AddressMode::REPEAT;
    AddressMode address_mode_v = AddressMode::REPEAT;
    AddressMode address_mode_w = AddressMode::REPEAT;
    float max_anisotropy = 1.0F; // 1.0 = disabled, 16.0 = max quality
    bool enable_mipmaps = false;
};

/**
 * @struct RenderConfig
 * @brief Unified rendering configuration for graphics buffers
 *
 * This is the persistent state that processors query and react to.
 * All rendering parameters in one place, independent of buffer type.
 * Child buffer classes populate it with context-specific defaults
 * during construction, then expose it to their processors.
 *
 * Design:
 * - Owned by VKBuffer as persistent state
 * - Processors query and react to changes
 * - Child classes have their own convenience RenderConfig with defaults
 *   that bridge to this Portal-level config
 */
struct RenderConfig {
    std::shared_ptr<Core::Window> target_window;
    std::string vertex_shader;
    std::string fragment_shader;
    std::string geometry_shader;
    std::string default_texture_binding;
    PrimitiveTopology topology { PrimitiveTopology::POINT_LIST };
    PolygonMode polygon_mode { PolygonMode::FILL };
    CullMode cull_mode { CullMode::NONE };

    std::vector<std::pair<std::string, std::shared_ptr<Core::VKImage>>> additional_textures;

    ///< For child-specific fields
    std::unordered_map<std::string, std::string> extra_string_params;

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

}
