#include <extra2d/app/application.h>
#include <extra2d/core/registry.h>
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/graphics/core/render_module.h>
#include <extra2d/graphics/memory/vram_manager.h>
#include <extra2d/platform/iinput.h>
#include <extra2d/platform/input_module.h>
#include <extra2d/platform/iwindow.h>
#include <extra2d/platform/window_module.h>
#include <extra2d/services/camera_service.h>
#include <extra2d/services/event_service.h>
#include <extra2d/services/logger_service.h>
#include <extra2d/services/scene_service.h>
#include <extra2d/services/timer_service.h>


namespace extra2d {

static double getTimeSeconds() {
#ifdef __SWITCH__
  struct timespec ts;
  clock_gettime(CLOCK_MONOTONIC, &ts);
  return static_cast<double>(ts.tv_sec) +
         static_cast<double>(ts.tv_nsec) / 1000000000.0;
#else
  using namespace std::chrono;
  auto now = steady_clock::now();
  auto duration = now.time_since_epoch();
  return duration_cast<std::chrono::duration<double>>(duration).count();
#endif
}

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

Application::Application() { Registry::instance().setApp(this); }

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

bool Application::init() {
  if (initialized_) {
    return true;
  }

  // 初始化所有模块（拓扑排序）
  // 服务通过 E2D_AUTO_REGISTER_SERVICE 宏自动注册
  if (!Registry::instance().init()) {
    return false;
  }

  // 配置相机服务（需要窗口信息）
  configureCameraService();

  // 初始化所有服务
  ServiceLocator::instance().initializeAll();

  initialized_ = true;
  running_ = true;
  return true;
}

void Application::configureCameraService() {
  auto *winMod = get<WindowModule>();
  if (!winMod || !winMod->win()) {
    return;
  }

  auto cameraService = ServiceLocator::instance().getService<ICameraService>();
  if (!cameraService) {
    return;
  }

  auto *win = winMod->win();
  cameraService->setViewport(0, static_cast<float>(win->width()),
                             static_cast<float>(win->height()), 0);

  ViewportConfig vpConfig;
  vpConfig.logicWidth = static_cast<float>(win->width());
  vpConfig.logicHeight = static_cast<float>(win->height());
  vpConfig.mode = ViewportMode::AspectRatio;
  cameraService->setViewportConfig(vpConfig);
  cameraService->updateViewport(win->width(), win->height());

  win->onResize([cameraService](int width, int height) {
    cameraService->updateViewport(width, height);
    cameraService->applyViewportAdapter();
  });
}

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

  VRAMMgr::get().printStats();

  ServiceLocator::instance().shutdownAll();
  ServiceLocator::instance().clear();
  Registry::instance().shutdown();
  Registry::instance().clear();

  initialized_ = false;
  running_ = false;
}

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

  auto *winMod = get<WindowModule>();
  if (!winMod || !winMod->win())
    return;

  lastFrameTime_ = getTimeSeconds();

  while (running_ && !winMod->win()->shouldClose()) {
    mainLoop();
  }
}

void Application::quit() {
  shouldQuit_ = true;
  running_ = false;
}

void Application::pause() {
  if (!paused_) {
    paused_ = true;
    ServiceLocator::instance().pauseAll();
  }
}

void Application::resume() {
  if (paused_) {
    paused_ = false;
    ServiceLocator::instance().resumeAll();
    lastFrameTime_ = getTimeSeconds();
  }
}

void Application::mainLoop() {
  double currentTime = getTimeSeconds();
  deltaTime_ = static_cast<float>(currentTime - lastFrameTime_);
  lastFrameTime_ = currentTime;

  totalTime_ += deltaTime_;

  frameCount_++;
  fpsTimer_ += deltaTime_;
  if (fpsTimer_ >= 1.0f) {
    currentFps_ = frameCount_;
    frameCount_ = 0;
    fpsTimer_ -= 1.0f;
  }

  auto *winMod = get<WindowModule>();
  if (winMod && winMod->win()) {
    winMod->win()->poll();
  }

  auto eventService = ServiceLocator::instance().getService<IEventService>();
  if (eventService) {
    eventService->processQueue();
  }

  if (!paused_) {
    update();
  }

  render();

  // 帧率限制
  auto *renderMod = get<RenderModule>();
  if (renderMod && renderMod->renderer()) {
    // 这里可以添加帧率限制逻辑
  }
}

void Application::update() {
  ServiceLocator::instance().updateAll(deltaTime_);

  auto *inputMod = get<InputModule>();
  if (inputMod) {
    inputMod->update();
  }
}

void Application::render() {
  auto *renderMod = get<RenderModule>();
  if (!renderMod || !renderMod->renderer())
    return;

  auto *renderer = renderMod->renderer();
  auto *winMod = get<WindowModule>();
  if (!winMod || !winMod->win())
    return;

  auto cameraService = ServiceLocator::instance().getService<ICameraService>();
  if (cameraService) {
    const auto &vp = cameraService->getViewportResult().viewport;
    renderer->setViewport(
        static_cast<int>(vp.origin.x), static_cast<int>(vp.origin.y),
        static_cast<int>(vp.size.width), static_cast<int>(vp.size.height));
    renderer->setViewProjection(cameraService->getViewProjectionMatrix());
  } else {
    renderer->setViewport(0, 0, winMod->win()->width(),
                          winMod->win()->height());
  }

  auto sceneService = ServiceLocator::instance().getService<ISceneService>();
  if (sceneService) {
    sceneService->render(*renderer);
  }

  winMod->win()->swap();
}

IWindow *Application::window() {
  auto *winMod = get<WindowModule>();
  return winMod ? winMod->win() : nullptr;
}

RenderBackend *Application::renderer() {
  auto *renderMod = get<RenderModule>();
  return renderMod ? renderMod->renderer() : nullptr;
}

IInput *Application::input() {
  auto *winMod = get<WindowModule>();
  return (winMod && winMod->win()) ? winMod->win()->input() : nullptr;
}

void Application::enterScene(Ptr<Scene> scene) {
  auto sceneService = ServiceLocator::instance().getService<ISceneService>();
  auto *winMod = get<WindowModule>();
  if (sceneService && scene && winMod && winMod->win()) {
    scene->setViewportSize(static_cast<float>(winMod->win()->width()),
                           static_cast<float>(winMod->win()->height()));
    sceneService->enterScene(scene);
  }
}

} // namespace extra2d
