#include "imgui.h"
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_gamepad.h>
#include <SDL3/SDL_init.h>
#include <SDL3/SDL_mouse.h>
#include <SDL3/SDL_scancode.h>
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL_main.h>
#include <SDL3/SDL.h>

#include <iostream>

#include "camera.h"
#include "renderer.h"

#include "imgui_impl_sdl3.h"

static Camera   camera;
static Renderer renderer;

static SDL_Gamepad* GetGamepad() {
  int count = 0;
  SDL_JoystickID* jids = SDL_GetGamepads(&count);

  SDL_Gamepad* gamepad = nullptr;
  for(int i = 0; i < count; i++) {
    SDL_Gamepad* candidate_gamepad = SDL_OpenGamepad(jids[i]);

    if(!gamepad) {
      gamepad = candidate_gamepad;
    }
  }

  if(!gamepad) {
    std::cerr << "No Gamepad :(" << std::endl;
  } else {    
    std::cerr << "Selected: " << SDL_GetGamepadName(gamepad) << std::endl;
  }

  SDL_free(jids);
  return gamepad;  
}

SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) {
  (void)appstate;
  (void)argc;
  (void)argv;
  SDL_Window* win = SDL_CreateWindow("Kale", 960, 540, SDL_WINDOW_RESIZABLE);
  SDL_SetWindowRelativeMouseMode(win, true);

  SDL_InitSubSystem(SDL_INIT_GAMEPAD);

  SDL_SetGamepadEventsEnabled(true);

  if (!renderer.init(win))
    return SDL_APP_FAILURE;

  renderer.gamepad = GetGamepad();

  return SDL_APP_CONTINUE;
}

SDL_AppResult SDL_AppIterate(void* appstate) {
  (void)appstate;
  camera.zoom = renderer.zoom;
  camera.on_gamepad(renderer.gamepad);
  camera.update();

  uint32_t sw_w = renderer.render_w;
  uint32_t sw_h = renderer.render_h;
  CameraUBO ubo = camera.ubo((float)sw_w / (float)(sw_h ? sw_h : 1));
  renderer.draw(ubo);

  return SDL_APP_CONTINUE;
}

SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
  (void)appstate;
  ImGui_ImplSDL3_ProcessEvent(event);
  switch (event->type) {
    case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
    case SDL_EVENT_QUIT:
      return SDL_APP_SUCCESS;
    case SDL_EVENT_GAMEPAD_ADDED:
      if(!renderer.gamepad)
        renderer.gamepad = SDL_OpenGamepad(event->gdevice.which);
    break;
    case SDL_EVENT_GAMEPAD_REMOVED:
      if (renderer.gamepad && SDL_GetGamepadID(renderer.gamepad) == event->gdevice.which) {
        SDL_CloseGamepad(renderer.gamepad);
        renderer.gamepad = nullptr;
      }
    break;
    case SDL_EVENT_KEY_DOWN:
      if(event->key.scancode == SDL_SCANCODE_ESCAPE) {
        renderer.in_menu = !renderer.in_menu;
        SDL_Window* win = SDL_GetWindowFromID(event->key.windowID);
        SDL_SetWindowRelativeMouseMode(win, !renderer.in_menu);
      } 
    case SDL_EVENT_KEY_UP:
      if(!renderer.in_menu)
        camera.on_key(event->key.scancode, event->type == SDL_EVENT_KEY_DOWN);
    break;
    case SDL_EVENT_MOUSE_MOTION:
      if(!renderer.in_menu)
        camera.on_mouse_motion(event->motion.xrel, event->motion.yrel);
    break;
  }
  return SDL_APP_CONTINUE;
}

void SDL_AppQuit(void* appstate, SDL_AppResult result) {
  (void)appstate;
  (void)result;
  renderer.destroy();
  SDL_DestroyWindow(renderer.win);
}
