#pragma once

#include <cstdint>
#include <string>
#include <unordered_map>

#include <imgui.h>

struct ID3D12Resource;

namespace minimap
{
    struct map_bounds;
    struct map_style_calibration;
    struct map_view_transform;
}

namespace svg_raster_map
{
    struct raster_layer
    {
        float width = 0.f;
        float height = 0.f;
        uint32_t raster_width = 0;
        uint32_t raster_height = 0;
        uint32_t cached_target_w = 0;
        uint64_t cache_signature = 0;
        ImTextureID tex_id = ImTextureID_Invalid;
        ID3D12Resource* dx12_resource = nullptr;
        bool has_tile_bounds = false;
        float tile_bounds_min_x = 0.f;
        float tile_bounds_max_x = 0.f;
        float tile_bounds_min_z = 0.f;
        float tile_bounds_max_z = 0.f;
        bool has_tile_projection = false;
        int tile_zoom = 0;
        float tile_pixel_min_x = 0.f;
        float tile_pixel_max_x = 0.f;
        float tile_pixel_min_y = 0.f;
        float tile_pixel_max_y = 0.f;
        float tile_transform[4]{1.f, 0.f, 0.395f, 0.f};
        int tile_coordinate_rotation = 0;
    };

    using layer_cache = std::unordered_map<std::string, raster_layer>;

    struct svg_document
    {
        std::string path;
        float world_span_m = 0.f;
        void* impl = nullptr;

        bool valid() const { return impl != nullptr; }
    };

    void release_layer_cache(layer_cache& layers);
    void release_svg_document(svg_document& doc);

    bool open_svg_document(const std::string& path, const float world_span_m, svg_document& out);
    bool svg_has_layer(const svg_document& doc, const std::string& layer_name);
    uint32_t default_raster_width(const svg_document& doc);
    float svg_width(const svg_document& doc);
    float svg_height(const svg_document& doc);

    bool ensure_layer_rasterized(svg_document& doc, layer_cache& cache, const std::string& layer_name,
                                 const uint32_t target_raster_width, const bool allow_async = false);

    bool load_layers_from_file(const std::string& path, layer_cache& out,
        float world_span_m = 0.f, float raster_scale_override = 0.f);

    void draw_layer(ImDrawList* draw_list, const raster_layer& layer, const minimap::map_view_transform& view,
                    int coordinate_rotation, float opacity_mul);
    void draw_layer_remapped(ImDrawList* draw_list, const raster_layer& layer,
                             const minimap::map_view_transform& view, int coordinate_rotation, float opacity_mul,
                             const minimap::map_bounds& source_bounds,
                             const minimap::map_style_calibration& target_calibration);
}