#include "ui/TilemapTab.h"

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

#include <iomanip>
#include <sstream>

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

namespace bmp2tile::ui
{

namespace
{

std::string DefaultTilemapSavePath(const std::string& imagePath, CompressionFormat format)
{
    const size_t dot = imagePath.find_last_of('.');
    const std::string base = (dot == std::string::npos) ? imagePath : imagePath.substr(0, dot);
    return base + ".tilemap." + CompressionFormatFileExtension(format);
}

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

}  // namespace

void DrawTilemapTab(App& app)
{
    if (!app.bHasImage)
    {
        ImGui::TextDisabled("Load an image on the Source tab first.");
        return;
    }

    ImGui::Text("%d x %d cells", app.CurrentTileSet.TilesWide, app.CurrentTileSet.TilesHigh);

    bool tilemapFlagsChanged = false;
    tilemapFlagsChanged |= ImGui::Checkbox("Use sprite palette", &app.bUseSpritePalette);
    ImGui::SameLine();
    tilemapFlagsChanged |= ImGui::Checkbox("In front of sprites", &app.bHighPriority);
    if (tilemapFlagsChanged)
    {
        app.RebuildTileSet();
    }

    DrawCompressionFormatCombo("Compression", app.TilemapCompressionFormat, SupportsTilemap);

    ImGui::InputInt("Index of first tile", &app.TileIndexOffset);
    if (app.TileIndexOffset != 0)
    {
        ImGui::TextDisabled("Added to every tile index below before saving -- for when your tiles won't be loaded starting at VRAM tile 0.");
    }

    if (ImGui::Button("Save tilemap..."))
    {
        const std::string ext = CompressionFormatFileExtension(app.TilemapCompressionFormat);
        const SDL_DialogFileFilter filters[] = {
            {"Tilemap data", ext.c_str()},
        };
        const std::string defaultPath = DefaultTilemapSavePath(app.LoadedPath, app.TilemapCompressionFormat);
        SDL_ShowSaveFileDialog(OnTilemapSaveDialogResult, &app, app.Window, filters, 1, defaultPath.c_str());
    }
    if (!app.LastSaveMessage.empty())
    {
        ImGui::SameLine();
        ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "%s", app.LastSaveMessage.c_str());
    }

    if (ImGui::CollapsingHeader("Include text (.dw format)"))
    {
        ImGui::TextDisabled("Uncompressed bytes only -- doesn't reflect the compression format selected above.");
        const std::string hex = FormatTilemapAsSmsHex(app.CurrentTileSet.Tilemap, app.CurrentTileSet.TilesWide);
        ImGui::InputTextMultiline("##tilemaphex", const_cast<char*>(hex.c_str()), hex.size() + 1, ImVec2(-1, 150),
                                   ImGuiInputTextFlags_ReadOnly);
    }

    ImGui::Separator();
    ImGui::TextDisabled("Debug preview: tile index + flip flags per cell (h/v suffixes), not an output format.");

    std::ostringstream out;
    for (int y = 0; y < app.CurrentTileSet.TilesHigh; ++y)
    {
        for (int x = 0; x < app.CurrentTileSet.TilesWide; ++x)
        {
            const auto& entry = app.CurrentTileSet.Tilemap[static_cast<size_t>(y) * app.CurrentTileSet.TilesWide + x];
            std::string cell = std::to_string(entry.TileIndex);
            if (entry.bHFlip) cell += 'h';
            if (entry.bVFlip) cell += 'v';
            out << std::setw(4) << cell << ' ';
        }
        out << '\n';
    }
    const std::string text = out.str();

    ImGui::InputTextMultiline("##tilemap", const_cast<char*>(text.c_str()), text.size() + 1, ImVec2(-1, -1),
                               ImGuiInputTextFlags_ReadOnly);
}

}  // namespace bmp2tile::ui
