#include "generate_animation_from_grid.hpp"

#include <algorithm>

#include "math.hpp"
#include "types.hpp"
#include "util/imgui/imgui.hpp"

using namespace anm2ed::types;
using namespace anm2ed::util;
using namespace glm;

namespace anm2ed::imgui::wizard
{
  GenerateAnimationFromGrid::GenerateAnimationFromGrid() : Canvas(vec2()) {}

  void GenerateAnimationFromGrid::update(Manager& manager, Document& document, Resources& resources, Settings& settings)
  {
    isEnd = false;

    auto& anm2 = document.anm2;
    auto& reference = document.reference;
    auto& startPosition = settings.generateStartPosition;
    auto& size = settings.generateSize;
    auto& pivot = settings.generatePivot;
    auto& rows = settings.generateRows;
    auto& columns = settings.generateColumns;
    auto& count = settings.generateCount;
    auto& delay = settings.generateDuration;
    auto& zoom = settings.generateZoom;
    auto& zoomStep = settings.inputZoomStep;

    auto childSize = ImVec2(row_widget_width_get(2), size_without_footer_get().y);

    if (ImGui::BeginChild("##Options Child", childSize, ImGuiChildFlags_Borders))
    {
      ImGui::InputInt2(localize.get(LABEL_GENERATE_START_POSITION), value_ptr(startPosition));
      ImGui::InputInt2(localize.get(LABEL_GENERATE_FRAME_SIZE), value_ptr(size));
      ImGui::InputInt2(localize.get(BASIC_PIVOT), value_ptr(pivot));
      ImGui::InputInt(localize.get(LABEL_GENERATE_ROWS), &rows, STEP, STEP_FAST);
      ImGui::InputInt(localize.get(LABEL_GENERATE_COLUMNS), &columns, STEP, STEP_FAST);

      input_int_range(localize.get(LABEL_GENERATE_COUNT), count, FRAME_NUM_MIN, rows * columns);

      ImGui::InputInt(localize.get(BASIC_DURATION), &delay, STEP, STEP_FAST);
    }
    ImGui::EndChild();

    rows = std::max(rows, 1);
    columns = std::max(columns, 1);
    count = std::clamp(count, FRAME_NUM_MIN, rows * columns);
    delay = std::max(delay, FRAME_DURATION_MIN);

    ImGui::SameLine();

    if (ImGui::BeginChild("##Preview Child", childSize, ImGuiChildFlags_Borders))
    {
      auto& backgroundColor = settings.previewBackgroundColor;
      auto& isTransparent = settings.animationPreviewTransparent;
      auto& shaderTexture = resources.shaders[resource::shader::TEXTURE];

      auto previewSize = ImVec2(ImGui::GetContentRegionAvail().x, size_without_footer_get(2).y);
      auto previewMin = ImGui::GetCursorScreenPos();
      auto previewMax = to_imvec2(to_vec2(previewMin) + to_vec2(previewSize));

      bind();
      size_set(to_vec2(previewSize));
      viewport_set();
      clear(isTransparent ? vec4(0) : vec4(backgroundColor, 1.0f));

      if (reference.itemType == LAYER)
      {
        auto layer = anm2.element_get(ElementType::LAYER_ELEMENT, reference.itemID);
        auto sourceTexture = layer ? document.texture_get(layer->spritesheetId) : nullptr;
        if (sourceTexture)
        {
          auto index = std::clamp((int)(time * (count - 1)), 0, (count - 1));
          auto row = index / columns;
          auto column = index % columns;
          auto crop = startPosition + ivec2(size.x * column, size.y * row);
          auto uvMin = (vec2(crop) + vec2(0.5f)) / vec2(sourceTexture->size);
          auto uvMax = (vec2(crop) + vec2(size) - vec2(0.5f)) / vec2(sourceTexture->size);

          mat4 transform = transform_get(zoom) * math::quad_model_get(size, {}, pivot);

          texture_render(shaderTexture, sourceTexture->id, transform, vec4(1.0f), {},
                         math::uv_vertices_get(uvMin, uvMax).data());
        }
      }

      unbind();

      if (isTransparent)
        render_checker_background(ImGui::GetWindowDrawList(), previewMin, previewMax, -to_vec2(previewSize) * 0.5f,
                                  CHECKER_SIZE);
      ImGui::Image(texture, previewSize);

      ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
      ImGui::SliderFloat("##Time", &time, 0.0f, 1.0f, "");

      ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
      ImGui::InputFloat("##Zoom", &zoom, zoomStep, zoomStep, "%.0f%%");
      zoom = glm::clamp(zoom, ZOOM_MIN, ZOOM_MAX);
    }

    ImGui::EndChild();

    auto widgetSize = widget_size_with_row_get(2);

    if (ImGui::Button(localize.get(LABEL_GENERATE), widgetSize))
    {
      auto queuedReference = reference;
      auto queuedStartPosition = startPosition;
      auto queuedSize = size;
      auto queuedPivot = pivot;
      auto queuedColumns = columns;
      auto queuedCount = count;
      auto queuedDelay = delay;

      manager.command_push({manager.selected,
                            [=](Manager&, Document& document)
                            {
                              auto itemType = static_cast<ItemType>(queuedReference.itemType);
                              auto item = document.anm2.element_get(queuedReference.animationIndex, itemType,
                                                                    queuedReference.itemID);
                              auto animation =
                                  document.anm2.element_get(ElementType::ANIMATION, queuedReference.animationIndex);

                              if (item && animation)
                              {
                                document.snapshot(localize.get(EDIT_GENERATE_ANIMATION_FROM_GRID));
                                frames_generate_from_grid(*item, queuedStartPosition, queuedSize, queuedPivot,
                                                          queuedColumns, queuedCount, queuedDelay);
                                animation->frameNum = animation_length_get(*animation);
                                document.anm2_change(Document::FRAMES);
                              }
                            }});
      isEnd = true;
    }

    ImGui::SameLine();

    if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize)) isEnd = true;
  }
}
