#pragma once

#include <vulkan/vulkan.h>
#include "SceneObject.h"
#include "ImageView.h"


/**
 * Represents a house object within a Vulkan-rendered scene.
 * Inherits from SceneObject to leverage common object properties and functionalities.
 */
class ScooterObject : public SceneObjectWithPhysics{
    public:

    
    
     /**
     * Constructor for the HouseObject.
     * Initializes the house geometry and invokes the base SceneObject constructor.
     * Scalability
     * 
     * @param dev The Vulkan device.
     * @param phyDev The physical Vulkan device.
     * @param descPool The descriptor pool for allocating descriptor sets.
     * @param descSetLayout The layout of the descriptor set.
     * @param queue The Vulkan queue to which rendering commands will be submitted.
     */
        ScooterObject(VkDevice dev, VkPhysicalDevice phyDev, VkDescriptorPool descPool, VkDescriptorSetLayout descSetLayout, VkQueue queue, 
            Physics::GamePhysicsManager& inputPhysicsManager, const glm::vec3& initialCollisionBoxPosition, const glm::vec3& initialCollisionBoxHalfSidelengths,
            VkSampler sampler,
            VkSampler specularSampler,
            VkSampler normalSampler,
            VkCommandPool cmdPool,
            bool sync,
            PFN_vkCmdPipelineBarrier2KHR pfn,
            ShadowMap& shadowMap,
            const float& inputMass = 0.0f)
        : SceneObjectWithPhysics(dev, phyDev, descPool, descSetLayout, queue, 
        {
            {{-1.0f, -1.0f, -1.0f}}, // Bottom-left back corner
            {{1.0f, -1.0f, -1.0f}},  // Bottom-right back corner
            {{1.0f, -1.0f, 1.0f}},   // Bottom-right front corner
            {{-1.0f, -1.0f, 1.0f}},  // Bottom-left front corner
            {{-1.0f, 1.0f, -1.0f}}, // Top-left back corner
            {{1.0f, 1.0f, -1.0f}},  // Top-right back corner
            {{1.0f, 1.0f, 1.0f}},   // Top-right front corner
            {{-1.0f, 1.0f, 1.0f}},  // Top-left front corner
        }, 
        {
            // Cube indices
            0, 1, 2, 2, 3, 0, // Front face
            1, 5, 6, 6, 2, 1, // Right face
            5, 4, 7, 7, 6, 5, // Back face
            4, 0, 3, 3, 7, 4, // Left face
            4, 5, 1, 1, 0, 4, // Bottom face
            3, 2, 6, 6, 7, 3  // Top face
        },
        inputPhysicsManager, initialCollisionBoxPosition, initialCollisionBoxHalfSidelengths,shadowMap, inputMass){
        // Initialization is mostly handled by the SceneObject constructor -- not anymore lol

        glm::mat4 localScale = glm::scale(glm::mat4(1.0f), glm::vec3(0.4f));
        uniformBuffer = vklCreateHostCoherentBufferWithBackingMemory(
            sizeof(UniformBuffer), VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
        );
        if (!load_from_obj("assets/meshes/Scooter.obj")) {
            throw std::runtime_error("Failed to load scooter.obj");
        }
        applyTransformationsLocal(this->data.positions, localScale);
        this->sceneObjectGeometry = createAndUploadIntoGpuMemory(data);

        ubo.ambientConstant = 0.1f; // Lower ambient reflection
        ubo.diffuseConstant = 0.2f; // Lower diffuse reflection
        ubo.specularConstant = 1.0f; // High specular reflection for metal
        ubo.shininessConstant = 32.0f;
 
    
        std::string texture_path = "assets/textures/KR51BaseColor.dds";
        ImageAndView texture = loadImage(dev, queue, cmdPool, texture_path, sync, pfn);

        descriptorSet = allocDescriptorSet(dev, descPool, descriptorSetLayout);          


        ImageAndView specularImageAndView = loadImage(device, queue, cmdPool, "assets/textures/KR51Metallic.dds", sync, pfn);

        ImageAndView normalImageAndView = loadImage(device, queue, cmdPool, "assets/textures/KR51Normal.dds", sync, pfn);

        // write shadowmap to correct binding in the descriptorset (default binding = 4)
        writeDescriptorSet(device, descriptorSet, shadowMap.m_image_view, shadowMap.m_image_sampler, shadowMap.m_descriptorBinding);

        writeDescriptorSet(device, descriptorSet, uniformBuffer, texture.view, sampler,  specularImageAndView.view, specularSampler, normalImageAndView.view, normalSampler);

                
        
        setObjectState(ObjectState::PhysicsControlled);

    }

    /**
     * Records the Vulkan rendering commands for the house object.
     * Binds the necessary Vulkan resources and issues the draw call.
     * 
     * @param commandBuffer The command buffer to record the rendering commands.
     * @param pipeline_layout The pipeline layout used for descriptor binding.
     * @param pipeline The graphics pipeline to use for rendering the house.
     */
    void recordRenderingCommands(VkCommandBuffer commandBuffer, VkPipeline pipeline, VkPipeline specularPipeline, VkPipeline normalPipeline, VkPipeline normalheightPipeline, const FrameTimer& frameTimer){
        
        drawGeometryWithMaterial(specularPipeline, this->sceneObjectGeometry, descriptorSet);
        for (auto& child : children) {
                child->recordRenderingCommands(commandBuffer, pipeline, specularPipeline, normalPipeline, normalheightPipeline, frameTimer);
        }

    }

    
    


};

