#pragma once
#include <SDL3/SDL.h>

#include <string>
#include <vector>

#include "core/Image.h"
#include "core/Palette.h"
#include "core/TileSet.h"

namespace bmp2tile
{

// Owns the SDL window/renderer, the ImGui context, and the currently-loaded
// image/tileset. The ui/*Tab.cpp files read and mutate this directly --
// there's no MVC layering here, this is a small tool, not a large app.
class App
{
public:
    bool Init();
    void Run();
    void Shutdown();

    // Loads a new image (see core/Image.h for supported formats) and
    // rebuilds the tileset + preview textures from it. On failure, sets
    // LastError and leaves any previously-loaded image in place.
    void LoadImageFile(const std::string& path);

    // Re-runs tile extraction with the current bRemoveDuplicates/bUseMirroring
    // settings and rebuilds the tile thumbnail textures. Call after changing
    // either flag from the UI.
    void RebuildTileSet();

    // Writes the current palette to `path` as raw %00BBGGRR bytes (see
    // core/Palette.h). On failure, sets LastError; on success, sets
    // LastSaveMessage and clears LastError.
    void SavePalette(const std::string& path);

    // Writes CurrentTileSet.Tiles/.Tilemap to `path` using
    // TilesCompressionFormat/TilemapCompressionFormat (see CompressionFormat
    // in core/TileSet.h). Same LastError/LastSaveMessage handling as
    // SavePalette.
    void SaveTiles(const std::string& path);
    void SaveTilemap(const std::string& path);

    SDL_Renderer* Renderer = nullptr;
    SDL_Window* Window = nullptr;

    bool bHasImage = false;
    IndexedImage CurrentImage;
    TileSet CurrentTileSet;
    bool bRemoveDuplicates = true;
    bool bUseMirroring = true;
    bool bSprite8x16 = false;
    bool bUseSpritePalette = false;
    bool bHighPriority = false;
    int ZoomPercent = 200;
    std::string LastError;
    std::string LastSaveMessage;
    std::string LoadedPath;

    // Bound to each tab's own format dropdown -- kept separate (rather
    // than one shared field) since tiles and tilemap can legitimately want
    // different formats, e.g. STC0 for tiles + STM for tilemap together.
    CompressionFormat TilesCompressionFormat = CompressionFormat::Uncompressed;
    CompressionFormat TilemapCompressionFormat = CompressionFormat::Uncompressed;

    // Bound to the Tilemap tab's "Index of first tile" field; added to
    // every tilemap entry's tile index before saving (OffsetTilemapTileIndices),
    // for when the tiles won't be loaded starting at VRAM tile 0.
    int TileIndexOffset = 0;

    // Bound to the Palette tab's format selector; drives both the hex/
    // constant text preview and (for Sms/Gg) the binary save.
    PaletteFormat CurrentPaletteFormat = PaletteFormat::Sms;

    // Bound to the Palette tab's "Always emit 16 colours" checkbox; when
    // set, PadPaletteTo16() is applied before formatting/saving so the
    // output always has a full 16 entries, padded with black, even if
    // the image itself uses fewer.
    bool bAlwaysEmit16Colours = false;

    SDL_Texture* SourceTexture = nullptr;
    std::vector<SDL_Texture*> TileTextures;  // parallel to CurrentTileSet.Tiles

private:
    void ProcessEvent(const SDL_Event& event);
    void RenderFrame();
    void RebuildSourceTexture();
    void RebuildTileTextures();
    void ReleaseTextures();

    bool bRunning = false;
};

}  // namespace bmp2tile
