#include "mapEditor.hpp"
#include "imgui.h"
#include "imgui_impl_sdl2.h"
#include "imgui_impl_sdlrenderer.h"
#include "map.hpp"
#include "mapEditorState.hpp"
#include "misc/cpp/imgui_stdlib.h"
#include "phoenix.hpp"
#include "state.hpp"
#include <SDL.h>
#include <SDL_events.h>
#include <SDL_keycode.h>
#include <stdio.h>

#if !SDL_VERSION_ATLEAST(2, 0, 17)
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
#endif

// Main code
void runMapEditor() {
  // Setup SDL
  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) !=
      0) {
    printf("Error: %s\n", SDL_GetError());
    return;
  }

  // From 2.0.18: Enable native IME.
#ifdef SDL_HINT_IME_SHOW_UI
  SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
#endif

  // Create window with SDL_Renderer graphics context
  SDL_WindowFlags window_flags =
      (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
  SDL_Window *window = SDL_CreateWindow(
      "Dear ImGui SDL2+SDL_Renderer example", SDL_WINDOWPOS_CENTERED,
      SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
  state.renderer = SDL_CreateRenderer(
      window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
  if (state.renderer == nullptr) {
    SDL_Log("Error creating SDL_Renderer!");
    return;
  }
  // SDL_RendererInfo info;
  // SDL_GetRendererInfo(renderer, &info);
  // SDL_Log("Current SDL_Renderer: %s", info.name);

  // Setup Dear ImGui context
  IMGUI_CHECKVERSION();
  ImGui::CreateContext();
  ImGuiIO &io = ImGui::GetIO();
  (void)io;
  io.ConfigFlags |=
      ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
  io.ConfigFlags |=
      ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls

  // Setup Dear ImGui style
  // ImGui::StyleColorsDark();
  ImGui::StyleColorsLight();

  // Setup Platform/Renderer backends
  ImGui_ImplSDL2_InitForSDLRenderer(window, state.renderer);
  ImGui_ImplSDLRenderer_Init(state.renderer);

  // Load Fonts
  // - If no fonts are loaded, dear imgui will use the default font. You can
  // also load multiple fonts and use ImGui::PushFont()/PopFont() to select
  // them.
  // - AddFontFromFileTTF() will return the ImFont* so you can store it if you
  // need to select the font among multiple.
  // - If the file cannot be loaded, the function will return a nullptr. Please
  // handle those errors in your application (e.g. use an assertion, or display
  // an error and quit).
  // - The fonts will be rasterized at a given size (w/ oversampling) and stored
  // into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which
  // ImGui_ImplXXXX_NewFrame below will call.
  // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype
  // for higher quality font rendering.
  // - Read 'docs/FONTS.md' for more instructions and details.
  // - Remember that in C/C++ if you want to include a backslash \ in a string
  // literal you need to write a double backslash \\ !
  // io.Fonts->AddFontDefault();
  // io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
  // io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
  // io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
  // io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
  // ImFont* font =
  // io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f,
  // nullptr, io.Fonts->GetGlyphRangesJapanese()); IM_ASSERT(font != nullptr);

  // Our state
  ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
  EditorGlobalState editorState{};

  // Load textures
  PRunBoostrap();

  // Main loop
  bool done = false;
  while (!done) {
    // Poll and handle events (inputs, window resize, etc.)
    // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to
    // tell if dear imgui wants to use your inputs.
    // - When io.WantCaptureMouse is true, do not dispatch mouse input data to
    // your main application, or clear/overwrite your copy of the mouse data.
    // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input
    // data to your main application, or clear/overwrite your copy of the
    // keyboard data. Generally you may always pass all inputs to dear imgui,
    // and hide them from your application based on those two flags.
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
      ImGui_ImplSDL2_ProcessEvent(&event);

      if (event.type == SDL_MOUSEBUTTONDOWN && !ImGui::IsAnyItemActive() &&
          !ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow) &&
          !ImGui::IsAnyItemHovered()) {
        if (event.button.button == SDL_BUTTON_LEFT) {
          if (editorState.placeTileMode) {
            editorState.currentMap.data.mapTiles.push_back(
                editorState.selectedTileName);
          }
        } else if (event.button.button == SDL_BUTTON_RIGHT) {
          if (editorState.placeTileMode) {
            editorState.currentMap.data.mapTiles.pop_back();
          }
        }
      }
      if (event.type == SDL_KEYDOWN) {
        if (event.key.keysym.scancode == SDL_SCANCODE_PAGEDOWN) {
          editorState.placeTileMode = !editorState.placeTileMode;
          SDL_Log("Toggled place tile on click");
        }
      }

      if (event.type == SDL_QUIT)
        done = true;
      if (event.type == SDL_WINDOWEVENT &&
          event.window.event == SDL_WINDOWEVENT_CLOSE &&
          event.window.windowID == SDL_GetWindowID(window))

        done = true;
    }

    // Start the Dear ImGui frame
    ImGui_ImplSDLRenderer_NewFrame();
    ImGui_ImplSDL2_NewFrame();
    ImGui::NewFrame();

    ImGui::Begin("Phoenix Map Editor");

    ImGui::Text("The Phoenix map editor outputs .map files which can be loaded "
                "by phoenix");
    ImGui::InputText("##Level file path", &editorState.mapFilePath);
    ImGui::SameLine();
    if (ImGui::Button("Load .map file")) {
      editorState.currentMap = PLoadMapFromFile(editorState.mapFilePath);
      editorState.loadedMap = true;
    }
    ImGui::End();

    if (editorState.loadedMap) {
      ImGui::Begin("Map Editor Tools");

      ImGui::Text("Keybinds:");
      ImGui::Text("PageDown : Toggle place tile on click");

      if (ImGui::Button("Save level file")) {
        PSaveMapToFile(&editorState.currentMap, editorState.mapFilePath);
      }

      const char *tileNames[] = {"WALL", "FLOOR"};

      ImGui::Text("Selected tile");
      ImGui::SameLine();
      if (ImGui::BeginCombo("##EditorSelectedTile",
                            editorState.selectedTileName)) {
        for (int i = 0; i < IM_ARRAYSIZE(tileNames); i++) {
          bool isSelected = (editorState.selectedTileName == tileNames[i]);
          if (ImGui::Selectable(tileNames[i], isSelected)) {
            editorState.selectedTileName = tileNames[i];
            SDL_Log("Selected tile: %s", editorState.selectedTileName);
          }

          if (isSelected) {
            ImGui::SetItemDefaultFocus();
          }
        }

        ImGui::EndCombo();
      }

      ImGui::End();
    }

    // Rendering
    ImGui::Render();
    SDL_RenderSetScale(state.renderer, io.DisplayFramebufferScale.x,
                       io.DisplayFramebufferScale.y);
    SDL_SetRenderDrawColor(state.renderer, (Uint8)(clear_color.x * 255),
                           (Uint8)(clear_color.y * 255),
                           (Uint8)(clear_color.z * 255),
                           (Uint8)(clear_color.w * 255));
    SDL_RenderClear(state.renderer);
    ImGui_ImplSDLRenderer_RenderDrawData(ImGui::GetDrawData());

    if (editorState.loadedMap) {
      PRenderMap(&editorState.currentMap);
    }

    SDL_RenderPresent(state.renderer);
  }

  // Cleanup
  ImGui_ImplSDLRenderer_Shutdown();
  ImGui_ImplSDL2_Shutdown();
  ImGui::DestroyContext();

  SDL_DestroyRenderer(state.renderer);
  SDL_DestroyWindow(window);
  SDL_Quit();
}
