#include "map.h"
#include "mini/surf/surf.h"
#include "mini/view/view.h"
#include "mini/draw/draw.h"

namespace mini
{
    namespace map
    {
        uint8_t tile_width = 8;
        uint8_t tile_height = 8;
        int map_surface = -1;

        void init() {

        }

        void quit() {
            map_surface = -1;
        }

        namespace surf {
            void set(uint8_t surface) {
                map_surface = surface;
            }

            uint8_t get()
            {
                return map_surface;
            }
        }

        void draw() {
            if (map_surface==-1 || mini::surf::state.source_surface==-1) return;

            const int tw = tile_width;
            const int th = tile_height;

            auto &m = mini::surf::state.surfaces[map_surface];

            int celw = m.w;
            int celh = m.h;

            int celx = 0;
            int cely = 0;

            int ox = view::state.origin[0];
            int oy = view::state.origin[1];

            int sx = ox;
            int sy = oy;

            auto &s = mini::surf::state.surfaces[mini::surf::state.dest_surface];

            // Clipping global rápido
            if (sx + celw * tw < s.clip[0] ||
                sy + celh * th < s.clip[1] ||
                sx > s.clip[2] ||
                sy > s.clip[3])
                return;

            // Recorte por izquierda
            if (sx < s.clip[0]) {
                int diff = (s.clip[0] - sx) / tw;
                celx += diff;
                celw -= diff;
                sx += diff * tw;
            }

            // Recorte por arriba
            if (sy < s.clip[1]) {
                int diff = (s.clip[1] - sy) / th;
                cely += diff;
                celh -= diff;
                sy += diff * th;
            }

            // Recorte por derecha
            int max_x = s.clip[2] - sx;
            if (max_x < celw * tw) celw = max_x / tw + 1;

            // Recorte por abajo
            int max_y = s.clip[3] - sy;
            if (max_y < celh * th) celh = max_y / th + 1;

            // Ahora sx, sy son relativos al origen y ya están recortados
            for (int y = 0; y < celh; ++y) {
                int ty = sy + y * th;
                for (int x = 0; x < celw; ++x) {
                    uint8_t tile = tile::get(celx + x, cely + y);
                    if (!tile) continue;
                    int tx = sx + x * tw;
                    draw::tileblit(tile, tx - ox, ty - oy, tile_width, tile_height);
                }
            }
        }

        namespace tile {
            uint8_t get(int celx, int cely) {
                if (map_surface==-1) return 0;
                auto &m = mini::surf::state.surfaces[map_surface];
                if (celx < 0 || celx > (m.w-1) || cely < 0 || cely > (m.h-1)) return 0;
                return m.p[celx+cely*m.w];
            }

            void set(int celx, int cely, uint8_t snum) {
                if (map_surface==-1) return;
                auto &m = mini::surf::state.surfaces[map_surface];
                if (celx < 0 || celx > (m.w-1) || cely < 0 || cely > (m.h-1)) return;
                m.p[celx+cely*m.w] = snum;
            }
        }

        namespace cell {
            uint8_t getw() { return tile_width; }
            uint8_t geth() { return tile_height; }
            
            void set(int w, int h) {
                tile_width = w;
                tile_height = h;
            }
        }

    }
}