#include <SDL2/SDL.h>
#include <algorithm>
#include <cstdio>
#include <frostbite2D/core/application.h>
#include <frostbite2D/graphics/renderer.h>
#include <frostbite2D/graphics/camera.h>
#include <frostbite2D/platform/switch.h>
#include <frostbite2D/types/type_math.h>
#include <frostbite2D/resource/asset.h>
#include <frostbite2D/scene/scene_manager.h>
namespace frostbite2D {

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

bool Application::init() {
  AppConfig cfg;
  return init(cfg);
}

bool Application::init(const AppConfig& config) {
  if (initialized_) {
    return true;
  }

  config_ = config;

  // 平台相关初始化
  #ifdef __SWITCH__
  switchInit();
  #endif

  // 使用SDL2创建窗口
  this->window_ = new Window();

  // 创建窗口会使用窗口配置
  if (!window_->create(config.windowConfig)) {
    SDL_Log("Failed to create window");
    return false;
  }

  // 初始化核心模块
  if (!initCoreModules()) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize core modules");
    shutdown();
    return false;
  }

  initialized_ = true;
  return true;
}

void Application::shutdown() {
  if (!initialized_)
    return;

  running_ = false;
  shouldQuit_ = true;

  // 关闭渲染器
  if (renderer_) {
    renderer_->shutdown();
    renderer_ = nullptr;
  }

  if (window_) {
    window_->destroy();
    window_ = nullptr;
  }

  // 清理相机
  if (camera_) {
    delete camera_;
    camera_ = nullptr;
  }

  // 平台相关清理
  #ifdef __SWITCH__
  switchShutdown();
  #endif

  initialized_ = false;
  running_ = false;
}

Application::~Application() {
  shutdown();
}

bool Application::initCoreModules() {

  // 初始化资产管理器
  auto &asset = Asset::get();

  // 平台相关 switch平台不可以获取当前工作目录
  #ifndef __SWITCH__
  // 获取程序工作目录
  std::string workingDir = SDL_GetBasePath();
  asset.setWorkingDirectory(workingDir);
  SDL_Log("Asset working directory: %s", workingDir.c_str());
  #else
  asset.setWorkingDirectory("/switch/Frostbite2D/" + config_.appName);
  SDL_Log("Asset working directory: %s", asset.getWorkingDirectory().c_str());
  #endif

  // 初始化渲染器
  renderer_ = &Renderer::get();
  if (!renderer_->init()) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize renderer");
    return false;
  }

  // 设置窗口清除颜色和视口
  renderer_->setClearColor(0.0f, 0.0f, 0.0f);
  renderer_->setViewport(0, 0, config_.windowConfig.width,
                         config_.windowConfig.height);

  // 创建并设置相机
  camera_ = new Camera();
  camera_->setViewport(config_.windowConfig.width, config_.windowConfig.height);
  camera_->setFlipY(true); // 启用 Y 轴翻转，(0,0) 在左上角
  renderer_->setCamera(camera_);

  return true;
}

void Application::run() {
  if (!initialized_) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Application not initialized!");
    return;
  }

  if (running_) {
    SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Application already running!");
    return;
  }

  SDL_Log("Starting application...");
  running_ = true;
  shouldQuit_ = false;
  paused_ = false;

  lastFrameTime_ = SDL_GetPerformanceCounter() / static_cast<double>(SDL_GetPerformanceFrequency());
  totalTime_ = 0.0f;
  deltaTime_ = 0.0f;
  frameCount_ = 0;
  fpsTimer_ = 0.0f;
  currentFps_ = 0;

  mainLoop();

  running_ = false;
  SDL_Log("Application stopped");
}

void Application::quit() {
  SDL_Log("Quit requested");
  shouldQuit_ = true;
}

void Application::pause() {
  if (!paused_) {
    SDL_Log("Application paused");
    paused_ = true;
  }
}

void Application::resume() {
  if (paused_) {
    SDL_Log("Application resumed");
    paused_ = false;
    lastFrameTime_ = SDL_GetPerformanceCounter() / static_cast<double>(SDL_GetPerformanceFrequency());
  }
}

void Application::mainLoop() {
  while (!shouldQuit_) {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) {
        shouldQuit_ = true;
        break;
      }
    }
    if (!paused_) {
      update();
    }

    render();
  }
}

void Application::update() {
  double currentTime = SDL_GetPerformanceCounter() / static_cast<double>(SDL_GetPerformanceFrequency());
  deltaTime_ = static_cast<float>(currentTime - lastFrameTime_);
  lastFrameTime_ = currentTime;
  totalTime_ += deltaTime_;

  SceneManager::get().Update(deltaTime_);

  frameCount_++;
  fpsTimer_ += deltaTime_;
  if (fpsTimer_ >= fpsUpdateInterval_) {
    currentFps_ = static_cast<int>(frameCount_ / fpsTimer_);
    frameCount_ = 0;
    fpsTimer_ = 0.0f;
  }
}

void Application::render() {
  Renderer& renderer = Renderer::get();

  renderer.beginFrame();
  SceneManager::get().Render();
  renderer.endFrame();

  if (window_) {
    window_->swap();
  }
}

const AppConfig& Application::getConfig() const {
  return config_;
}
} // namespace frostbite2D
