#include "ui/SourceTab.h"

#include <SDL3/SDL.h>
#include <imgui.h>

#include "App.h"
#include "core/TileSet.h"

namespace bmp2tile::ui
{

namespace
{

// Invoked by SDL once the native open dialog closes. See the matching
// callback in PaletteTab.cpp for the main-thread note.
void OnSourceOpenDialogResult(void* userdata, const char* const* filelist, int /*filter*/)
{
    App& app = *static_cast<App*>(userdata);
    if (!filelist)
    {
        app.LastError = std::string("Open dialog error: ") + SDL_GetError();
        return;
    }
    if (!filelist[0])
    {
        return;  // user cancelled -- nothing to do
    }
    app.LoadImageFile(filelist[0]);
}

}  // namespace

void DrawSourceTab(App& app)
{
    ImGui::TextWrapped(
        "Drag and drop a BMP, PNG or GIF onto this window, or use Open below. "
        "Indexed (1/4/8bpp) BMP is recommended so the palette order is preserved exactly.");

    if (ImGui::Button("Open..."))
    {
        const SDL_DialogFileFilter filters[] = {
            {"Images", "bmp;png;gif"},
        };
        SDL_ShowOpenFileDialog(OnSourceOpenDialogResult, &app, app.Window, filters, 1, nullptr, false);
    }

    if (!app.bHasImage)
    {
        return;
    }

    ImGui::Separator();
    ImGui::Text("%dx%d px, %zu colours, loaded from %s", app.CurrentImage.Width, app.CurrentImage.Height,
                app.CurrentImage.Palette.size(), app.LoadedPath.c_str());

    ImGui::SliderInt("Zoom %", &app.ZoomPercent, 25, 800);
    ImGui::SameLine();
    static bool bShowGrid = true;
    ImGui::Checkbox("Show tile grid", &bShowGrid);

    const float scale = app.ZoomPercent / 100.0f;
    const ImVec2 imageSize(app.CurrentImage.Width * scale, app.CurrentImage.Height * scale);

    ImGui::BeginChild("SourceScroll", ImVec2(0, 0), true, ImGuiWindowFlags_HorizontalScrollbar);

    const ImVec2 imageTopLeft = ImGui::GetCursorScreenPos();
    if (app.SourceTexture)
    {
        // If a future ImGui upgrade changes this convention, see
        // examples/example_sdl3_sdlrenderer3 in the imgui repo for the
        // current one.
        ImGui::GetWindowDrawList()->AddCallback(ImGui::GetPlatformIO().DrawCallback_SetSamplerNearest);
        ImGui::Image(reinterpret_cast<ImTextureID>(app.SourceTexture), imageSize);
        // Must be restored before the grid lines below, whose antialiasing needs bilinear.
        ImGui::GetWindowDrawList()->AddCallback(ImGui::GetPlatformIO().DrawCallback_SetSamplerLinear);
    }
    else
    {
        ImGui::Dummy(imageSize);
    }

    if (bShowGrid)
    {
        ImDrawList* drawList = ImGui::GetWindowDrawList();
        const ImU32 gridColor = IM_COL32(0, 255, 120, 160);
        const float cellPx = TileSize * scale;

        for (int tx = 0; tx <= app.CurrentTileSet.TilesWide; ++tx)
        {
            const float x = imageTopLeft.x + tx * cellPx;
            drawList->AddLine(ImVec2(x, imageTopLeft.y), ImVec2(x, imageTopLeft.y + imageSize.y), gridColor);
        }
        for (int ty = 0; ty <= app.CurrentTileSet.TilesHigh; ++ty)
        {
            const float y = imageTopLeft.y + ty * cellPx;
            drawList->AddLine(ImVec2(imageTopLeft.x, y), ImVec2(imageTopLeft.x + imageSize.x, y), gridColor);
        }
    }

    ImGui::EndChild();
}

}  // namespace bmp2tile::ui
