#include <SDL2/SDL.h>
#include <SDL2/SDL_events.h>
#include <algorithm>
#include <cstdio>
#include <memory>
#include <frostbite2D/audio/audio_system.h>
#include <frostbite2D/base/object_registry.h>
#include <frostbite2D/core/application.h>
#include <frostbite2D/core/task_system.h>
#include <frostbite2D/event/event.h>
#include <frostbite2D/event/key_event.h>
#include <frostbite2D/event/mouse_event.h>
#include <frostbite2D/event/touch_event.h>
#include <frostbite2D/event/joystick_event.h>
#include <frostbite2D/event/window_event.h>
#include <frostbite2D/graphics/camera.h>
#include <frostbite2D/graphics/renderer.h>
#include <frostbite2D/platform/switch.h>
#include <frostbite2D/platform/windows.h>
#include <frostbite2D/resource/asset.h>
#include <frostbite2D/resource/npk_archive.h>
#include <frostbite2D/resource/pvf_archive.h>
#include <frostbite2D/resource/sound_pack_archive.h>
#include <frostbite2D/scene/scene.h>
#include <frostbite2D/scene/scene_manager.h>
#include <frostbite2D/types/type_math.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

  #ifdef _WIN32
  windowsInit();
  #endif

  // 初始化核心模块
  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;

  TaskSystem::get().shutdown();

  // 单例销毁（反向初始化顺序）
  // 场景管理
  SceneManager::get().ClearAll();

  // 渲染器（内部会清理 ShaderManager 和 Batch）
  Renderer::get().shutdown();

  // 音频系统
  AudioSystem::get().shutdown();

  // 资源归档
  NpkArchive::get().close();
  PvfArchive::get().close();
  SoundPackArchive::get().close();

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

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

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

  // 退出 SDL（添加重复调用保护）
  static bool sdlQuitCalled = false;
  if (!sdlQuitCalled) {
    SDL_Quit();
    sdlQuitCalled = true;
  }

  ObjectRegistry::get().clear();

  initialized_ = false;
  running_ = false;
}

Application::~Application() {
  
}

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
  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER) != 0) {
    SDL_Log("Failed to initialize SDL: %s", SDL_GetError());
    return false;
  }

  // 打开第一个手柄（如果存在）
  if (SDL_GameController *controller = SDL_GameControllerOpen(0)) {
    SDL_Log("GameController opened: %s", SDL_GameControllerName(controller));
  } else {
    SDL_Log("No GameController found");
  }

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

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

  window_->onResize([this](int width, int height) {
    renderer_->setViewport(0, 0, width, height);
    camera_->setViewport(width, height);
    SDL_Log("Window resized to %dx%d", width, height);
  });

  // 初始化渲染器
  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_);

  if (!TaskSystem::get().init()) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize task system");
    return false;
  }

  return true;
}

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

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


  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;

  if (callback) {
    callback();
  }

  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 sdlEvent;
    while (SDL_PollEvent(&sdlEvent)) {
      if (sdlEvent.type == SDL_QUIT) {
        shouldQuit_ = true;
        break;
      }

      auto event = convertSDLEvent(sdlEvent);
      if (event) {
        dispatchEvent(*event);
      }
    }

    TaskSystem::get().drainMainThreadTasks();

    if (!paused_) {
      update();
    }

    render();
  }
}

std::unique_ptr<Event> Application::convertSDLEvent(const SDL_Event& sdlEvent) {
  switch (sdlEvent.type) {
    case SDL_WINDOWEVENT: {
      switch (sdlEvent.window.event) {
        case SDL_WINDOWEVENT_CLOSE:
          return std::make_unique<WindowCloseEvent>(sdlEvent.window.timestamp, sdlEvent.window.windowID);
        case SDL_WINDOWEVENT_RESIZED:
        case SDL_WINDOWEVENT_SIZE_CHANGED:
          return std::make_unique<WindowResizeEvent>(sdlEvent.window.timestamp, sdlEvent.window.windowID, 
                                                     sdlEvent.window.data1, sdlEvent.window.data2);
        case SDL_WINDOWEVENT_FOCUS_GAINED:
        case SDL_WINDOWEVENT_FOCUS_LOST:
          return std::make_unique<WindowFocusEvent>(sdlEvent.window.timestamp, sdlEvent.window.windowID,
                                                     sdlEvent.window.event == SDL_WINDOWEVENT_FOCUS_GAINED);
        case SDL_WINDOWEVENT_MINIMIZED:
          return std::make_unique<WindowMinimizeEvent>(sdlEvent.window.timestamp, sdlEvent.window.windowID);
        case SDL_WINDOWEVENT_MAXIMIZED:
          return std::make_unique<WindowMaximizeEvent>(sdlEvent.window.timestamp, sdlEvent.window.windowID);
        case SDL_WINDOWEVENT_RESTORED:
          return std::make_unique<WindowRestoreEvent>(sdlEvent.window.timestamp, sdlEvent.window.windowID);
      }
      break;
    }

    case SDL_KEYDOWN: {
      return std::make_unique<KeyEvent>(sdlEvent.key.timestamp, 
                                        static_cast<KeyCode>(sdlEvent.key.keysym.sym),
                                        static_cast<KeyMod>(sdlEvent.key.keysym.mod),
                                        sdlEvent.key.repeat != 0);
    }

    case SDL_KEYUP: {
      return std::make_unique<KeyUpEvent>(sdlEvent.key.timestamp,
                                          static_cast<KeyCode>(sdlEvent.key.keysym.sym),
                                          static_cast<KeyMod>(sdlEvent.key.keysym.mod));
    }

    case SDL_TEXTINPUT: {
      return std::make_unique<KeyTextEvent>(sdlEvent.text.timestamp, sdlEvent.text.text);
    }

    case SDL_MOUSEMOTION: {
      return std::make_unique<MouseMoveEvent>(sdlEvent.motion.timestamp,
                                               Vec2(static_cast<float>(sdlEvent.motion.x), static_cast<float>(sdlEvent.motion.y)),
                                               Vec2(static_cast<float>(sdlEvent.motion.xrel), static_cast<float>(sdlEvent.motion.yrel)));
    }

    case SDL_MOUSEBUTTONDOWN: {
      return std::make_unique<MouseButtonEvent>(sdlEvent.button.timestamp,
                                                 static_cast<MouseButton>(sdlEvent.button.button),
                                                 Vec2(static_cast<float>(sdlEvent.button.x), static_cast<float>(sdlEvent.button.y)),
                                                 true);
    }

    case SDL_MOUSEBUTTONUP: {
      return std::make_unique<MouseButtonEvent>(sdlEvent.button.timestamp,
                                                 static_cast<MouseButton>(sdlEvent.button.button),
                                                 Vec2(static_cast<float>(sdlEvent.button.x), static_cast<float>(sdlEvent.button.y)),
                                                 false);
    }

    case SDL_MOUSEWHEEL: {
      return std::make_unique<MouseWheelEvent>(sdlEvent.wheel.timestamp,
                                                  Vec2(static_cast<float>(sdlEvent.wheel.mouseX), static_cast<float>(sdlEvent.wheel.mouseY)),
                                                  Vec2(static_cast<float>(sdlEvent.wheel.x), static_cast<float>(sdlEvent.wheel.y)),
                                                  sdlEvent.wheel.direction == SDL_MOUSEWHEEL_FLIPPED);
    }

    case SDL_FINGERDOWN: {
      return std::make_unique<TouchDownEvent>(sdlEvent.tfinger.timestamp,
                                               sdlEvent.tfinger.touchId,
                                               sdlEvent.tfinger.fingerId,
                                               Vec2(static_cast<float>(sdlEvent.tfinger.x), static_cast<float>(sdlEvent.tfinger.y)),
                                               sdlEvent.tfinger.pressure);
    }

    case SDL_FINGERUP: {
      return std::make_unique<TouchUpEvent>(sdlEvent.tfinger.timestamp,
                                             sdlEvent.tfinger.touchId,
                                             sdlEvent.tfinger.fingerId,
                                             Vec2(static_cast<float>(sdlEvent.tfinger.x), static_cast<float>(sdlEvent.tfinger.y)),
                                             sdlEvent.tfinger.pressure);
    }

    case SDL_FINGERMOTION: {
      return std::make_unique<TouchMoveEvent>(sdlEvent.tfinger.timestamp,
                                               sdlEvent.tfinger.touchId,
                                               sdlEvent.tfinger.fingerId,
                                               Vec2(static_cast<float>(sdlEvent.tfinger.x), static_cast<float>(sdlEvent.tfinger.y)),
                                               Vec2(static_cast<float>(sdlEvent.tfinger.dx), static_cast<float>(sdlEvent.tfinger.dy)),
                                               sdlEvent.tfinger.pressure);
    }

    case SDL_CONTROLLERBUTTONDOWN: {
      return std::make_unique<JoystickButtonDownEvent>(sdlEvent.cbutton.timestamp,
                                                         sdlEvent.cbutton.which,
                                                         sdlEvent.cbutton.button);
    }

    case SDL_CONTROLLERBUTTONUP: {
      return std::make_unique<JoystickButtonUpEvent>(sdlEvent.cbutton.timestamp,
                                                       sdlEvent.cbutton.which,
                                                       sdlEvent.cbutton.button);
    }

    case SDL_CONTROLLERAXISMOTION: {
      return std::make_unique<JoystickAxisEvent>(sdlEvent.caxis.timestamp,
                                                  sdlEvent.caxis.which,
                                                  sdlEvent.caxis.axis,
                                                  sdlEvent.caxis.value);
    }
  }

  return nullptr;
}

void Application::dispatchEvent(const Event& event) {
  Scene* currentScene = SceneManager::get().GetCurrentScene();
  if (currentScene) {
    currentScene->OnEvent(event);
  }
}

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
