#include "Shader.h"
#include <fstream>
#include <sstream>
#include <iostream>

Shader::~Shader()
{
    if (m_ProgramID)
        glDeleteProgram(m_ProgramID);
}

bool Shader::Load(const std::string& vertexPath, const std::string& fragmentPath)
{
    // 1) Create shader objects
    GLuint vertexShader   = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);

    // 2) Load sources
    std::string vertSource = LoadSourceFromFile(vertexPath);
    std::string fragSource = LoadSourceFromFile(fragmentPath);
    if (vertSource.empty() || fragSource.empty())
    {
        std::cerr << "[Shader] Failed to read shader files." << std::endl;
        return false;
    }

    // 3) Compile vertex shader
    {
        const char* src = vertSource.c_str();
        glShaderSource(vertexShader, 1, &src, nullptr);
        glCompileShader(vertexShader);
        if (!CompileShader(vertexShader, vertexPath))
            return false;
    }

    // 4) Compile fragment shader
    {
        const char* src = fragSource.c_str();
        glShaderSource(fragmentShader, 1, &src, nullptr);
        glCompileShader(fragmentShader);
        if (!CompileShader(fragmentShader, fragmentPath))
            return false;
    }

    // 5) Create program and link
    m_ProgramID = glCreateProgram();
    glAttachShader(m_ProgramID, vertexShader);
    glAttachShader(m_ProgramID, fragmentShader);
    glLinkProgram(m_ProgramID);

    // Check link status
    GLint success;
    glGetProgramiv(m_ProgramID, GL_LINK_STATUS, &success);
    if (!success)
    {
        char infoLog[1024];
        glGetProgramInfoLog(m_ProgramID, 1024, nullptr, infoLog);
        std::cerr << "[Shader] Program linking failed:\n" << infoLog << std::endl;
        return false;
    }

    // Cleanup shader objects after linking
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return true;
}

bool Shader::CompileShader(GLuint shaderID, const std::string& filePath)
{
    GLint success;
    glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        char infoLog[1024];
        glGetShaderInfoLog(shaderID, 1024, nullptr, infoLog);
        std::cerr << "[Shader] Compilation error in " << filePath << ":\n" 
                  << infoLog << std::endl;
        return false;
    }
    return true;
}

std::string Shader::LoadSourceFromFile(const std::string& filePath)
{
    std::ifstream file(filePath);
    if (!file.is_open()) 
    {
        std::cerr << "[Shader] Could not open file: " << filePath << std::endl;
        return "";
    }
    std::stringstream buffer;
    buffer << file.rdbuf();
    return buffer.str();
}