#include <frostbite2D/graphics/font_manager.h>
#include <frostbite2D/resource/asset.h>
#include <SDL2/SDL.h>

namespace frostbite2D {

FontManager::~FontManager() {
  unloadAll();
}

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

bool FontManager::init() {
  if (TTF_WasInit() == 0) {
    if (TTF_Init() != 0) {
      SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize TTF: %s", TTF_GetError());
      return false;
    }
  }
  return true;
}

void FontManager::shutdown() {
  unloadAll();
  if (TTF_WasInit() != 0) {
    TTF_Quit();
  }
}

bool FontManager::registerFont(const std::string& name, const std::string& path, int fontSize) {
  if (fonts_.find(name) != fonts_.end()) {
    SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Font '%s' already registered, replacing", name.c_str());
    unregisterFont(name);
  }

  Asset& asset = Asset::get();
  std::string fullPath = asset.resolveAssetPath(path);
  
  TTF_Font* font = TTF_OpenFont(fullPath.c_str(), fontSize);
  if (!font) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load font '%s': %s", fullPath.c_str(), TTF_GetError());
    return false;
  }

  fonts_[name] = font;
  
  FontInfo info;
  info.name = name;
  info.path = path;
  info.size = fontSize;
  fontInfos_[name] = info;
  
  SDL_Log("Font '%s' loaded: %s, size %d", name.c_str(), fullPath.c_str(), fontSize);
  return true;
}

TTF_Font* FontManager::getFont(const std::string& name) {
  auto it = fonts_.find(name);
  if (it == fonts_.end()) {
    SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Font '%s' not found", name.c_str());
    return nullptr;
  }
  return it->second;
}

bool FontManager::hasFont(const std::string& name) const {
  return fonts_.find(name) != fonts_.end();
}

void FontManager::unregisterFont(const std::string& name) {
  auto it = fonts_.find(name);
  if (it != fonts_.end()) {
    TTF_CloseFont(it->second);
    fonts_.erase(it);
    fontInfos_.erase(name);
  }
}

void FontManager::unloadAll() {
  for (auto& pair : fonts_) {
    TTF_CloseFont(pair.second);
  }
  fonts_.clear();
  fontInfos_.clear();
}

std::optional<FontManager::FontInfo> FontManager::getFontInfo(const std::string& name) const {
  auto it = fontInfos_.find(name);
  if (it != fontInfos_.end()) {
    return it->second;
  }
  return std::nullopt;
}

}
