#include "SDL_log.h"
#include <SDL2/SDL.h>
#include <frostbite2D/graphics/shader_manager.h>
#include <frostbite2D/graphics/shader.h>
#include <frostbite2D/resource/asset.h>
#include <json/json.hpp>
#include <fstream>
#include <sstream>
#include <glad/glad.h>

using json = nlohmann::json;

using json = nlohmann::json;

namespace frostbite2D {

ShaderManager& ShaderManager::get() {
  static ShaderManager instance;
  return instance;
}

// 移除析构函数中的自动销毁，改为在 Application::shutdown() 中手动调用

bool ShaderManager::init(const std::string& shadersDir) {
  shadersDir_ = shadersDir;
  shaders_.clear();
  
  std::string configPath = shadersDir_ + "/shaders.json";
  return loadShadersFromConfig(configPath);
}

void ShaderManager::shutdown() {
  shaders_.clear();
}

Shader* ShaderManager::getShader(const std::string& name) {
  auto it = shaders_.find(name);
  if (it != shaders_.end()) {
    return it->second.Get();
  }
  SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Shader not found: %s", name.c_str());
  return nullptr;
}

bool ShaderManager::hasShader(const std::string& name) const {
  return shaders_.find(name) != shaders_.end();
}

bool ShaderManager::loadShader(const std::string& name, const std::string& vertPath, 
                                const std::string& fragPath) {
  Asset& asset = Asset::get();
  std::string vertSource, fragSource;
  
  if (!asset.readTextFile(vertPath, vertSource)) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load vertex shader: %s", vertPath.c_str());
    return false;
  }
  
  if (!asset.readTextFile(fragPath, fragSource)) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load fragment shader: %s", fragPath.c_str());
    return false;
  }
  
  uint32_t vertexID = glCreateShader(GL_VERTEX_SHADER);
  uint32_t fragmentID = glCreateShader(GL_FRAGMENT_SHADER);
  
  const char* vertSrc = vertSource.c_str();
  glShaderSource(vertexID, 1, &vertSrc, nullptr);
  glCompileShader(vertexID);
  
  const char* fragSrc = fragSource.c_str();
  glShaderSource(fragmentID, 1, &fragSrc, nullptr);
  glCompileShader(fragmentID);
  
  int success;
  glGetShaderiv(vertexID, GL_COMPILE_STATUS, &success);
  if (!success) {
    int length;
    glGetShaderiv(vertexID, GL_INFO_LOG_LENGTH, &length);
    std::vector<char> log(length);
    glGetShaderInfoLog(vertexID, length, &length, log.data());
    
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Vertex shader compilation failed: %s", log.data());
    glDeleteShader(vertexID);
    glDeleteShader(fragmentID);
    return false;
  }
  
  glGetShaderiv(fragmentID, GL_COMPILE_STATUS, &success);
  if (!success) {
    int length;
    glGetShaderiv(fragmentID, GL_INFO_LOG_LENGTH, &length);
    std::vector<char> log(length);
    glGetShaderInfoLog(fragmentID, length, &length, log.data());
    
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Fragment shader compilation failed: %s", log.data());
    glDeleteShader(vertexID);
    glDeleteShader(fragmentID);
    return false;
  }
  
  uint32_t programID = glCreateProgram();
  glAttachShader(programID, vertexID);
  glAttachShader(programID, fragmentID);
  
  // 绑定顶点属性位置，确保和 Batch 类的设置一致
  glBindAttribLocation(programID, 0, "a_position");
  glBindAttribLocation(programID, 1, "a_texCoord");
  glBindAttribLocation(programID, 2, "a_color");
  
  glLinkProgram(programID);
  
  glGetProgramiv(programID, GL_LINK_STATUS, &success);
  if (!success) {
    int length;
    glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &length);
    std::vector<char> log(length);
    glGetProgramInfoLog(programID, length, &length, log.data());
    
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Shader linking failed: %s", log.data());
    glDeleteProgram(programID);
    glDeleteShader(vertexID);
    glDeleteShader(fragmentID);
    return false;
  }
  
  glDeleteShader(vertexID);
  glDeleteShader(fragmentID);
  
  auto shader = Ptr<Shader>(new Shader(name, programID));
  shaders_[name] = shader;
  
  SDL_Log("Loaded shader: %s", name.c_str());
  return true;
}

bool ShaderManager::loadShadersFromConfig(const std::string& configPath) {
  Asset& asset = Asset::get();
  std::string content;
  
  if (!asset.readTextFile(configPath, content)) {
    SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "No shaders.json found, will compile shaders on demand");
    return true;
  }
  
  try {
    json config = json::parse(content);
    
    if (!config.contains("shaders")) {
      SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid shaders.json: missing 'shaders' key");
      return false;
    }
    
    auto shaders = config["shaders"];
    for (auto& [key, value] : shaders.items()) {
      if (!value.contains("vertex") || !value.contains("fragment")) {
        SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Invalid shader entry: %s", key.c_str());
        continue;
      }
      
      std::string vertFile = value["vertex"];
      std::string fragFile = value["fragment"];
      
      std::string vertPath = shadersDir_ + "/" + vertFile;
      std::string fragPath = shadersDir_ + "/" + fragFile;
      
      if (!loadShader(key, vertPath, fragPath)) {
        SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Failed to load shader: %s", key.c_str());
      }
    }
    
    SDL_Log("Loaded %zu shaders from config", shaders_.size());
    return true;
    
  } catch (const json::parse_error& e) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to parse shaders.json: %s", e.what());
    return false;
  } catch (const std::exception& e) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error loading shaders: %s", e.what());
    return false;
  }
}

}