#include "room_types.h"
#include "ca.h"
#include <string.h>

static int carve_small_rect(grid_t g, rng_t *rng, int cx, int cy, uint8_t room_id) {
    int w = rng_range(rng, 3, 6);
    int h = rng_range(rng, 2, 4);
    int x = cx - w / 2;
    int y = cy - h / 2;
    if (x < 1 || y < 1 || x + w >= DCOLS - 1 || y + h >= DROWS - 1) return 0;
    grid_draw_rect(g, x, y, w, h, T_FLOOR, room_id);
    return 1;
}

static int carve_cross(grid_t g, rng_t *rng, int cx, int cy, uint8_t room_id) {
    int majw = rng_range(rng, 4, 8);
    int majh = rng_range(rng, 3, 4);
    int minw = rng_range(rng, 3, 5);
    int minh = rng_range(rng, 2, 3);
    int ax = cx - majw / 2, ay = cy - majh / 2;
    int bx = cx - minw / 2, by = cy - minh / 2;
    if (ax < 1 || ay < 1 || ax + majw >= DCOLS - 1 || ay + majh >= DROWS - 1) return 0;
    if (bx < 1 || by < 1 || bx + minw >= DCOLS - 1 || by + minh >= DROWS - 1) return 0;
    grid_draw_rect(g, ax, ay, majw, majh, T_FLOOR, room_id);
    grid_draw_rect(g, bx, by, minw, minh, T_FLOOR, room_id);
    return 1;
}

static int carve_sym_cross(grid_t g, rng_t *rng, int cx, int cy, uint8_t room_id) {
    int majw = rng_range(rng, 4, 8) | 1;
    int majh = 3;
    int minw = 3;
    int minh = rng_range(rng, 3, 5) | 1;
    int ax = cx - majw / 2, ay = cy - majh / 2;
    int bx = cx - minw / 2, by = cy - minh / 2;
    if (ax < 1 || ay < 1 || ax + majw >= DCOLS - 1 || ay + majh >= DROWS - 1) return 0;
    if (bx < 1 || by < 1 || bx + minw >= DCOLS - 1 || by + minh >= DROWS - 1) return 0;
    grid_draw_rect(g, ax, ay, majw, majh, T_FLOOR, room_id);
    grid_draw_rect(g, bx, by, minw, minh, T_FLOOR, room_id);
    return 1;
}

static int carve_circular(grid_t g, rng_t *rng, int cx, int cy, uint8_t room_id) {
    int r = rng_range(rng, 2, 4);
    if (cx - r < 1 || cy - r < 1 || cx + r >= DCOLS - 1 || cy + r >= DROWS - 1) return 0;
    grid_draw_circle(g, cx, cy, r, T_FLOOR, room_id);
    return 1;
}

static int carve_chunky(grid_t g, rng_t *rng, int cx, int cy, uint8_t room_id) {
    int bumps = rng_range(rng, 2, 4);
    int placed = 0;
    for (int i = 0; i < bumps; i++) {
        int ox = rng_range(rng, -2, 2);
        int oy = rng_range(rng, -2, 2);
        int r = rng_range(rng, 1, 2);
        int x = cx + ox, y = cy + oy;
        if (x - r < 1 || y - r < 1 || x + r >= DCOLS - 1 || y + r >= DROWS - 1) continue;
        grid_draw_circle(g, x, y, r, T_FLOOR, room_id);
        placed++;
    }
    return placed > 0;
}

/* Carve a CA blob into the scratch grid, then transcribe filled cells as
   T_FLOOR with the given room_id. The blob is generated centered on (cx,cy)
   with the given bounding box (clipped to grid). Returns 1 if any cells got
   carved. ca_blob is called with NULL sink to avoid spamming CA_ITERATION
   events from inside accretion. */
static int carve_ca_blob(grid_t g, rng_t *rng, int cx, int cy,
                         int bw, int bh, uint8_t room_id) {
    int x0 = cx - bw / 2;
    int y0 = cy - bh / 2;
    if (x0 < 1) x0 = 1;
    if (y0 < 1) y0 = 1;
    if (x0 + bw >= DCOLS - 1) x0 = DCOLS - 1 - bw;
    if (y0 + bh >= DROWS - 1) y0 = DROWS - 1 - bh;
    if (x0 < 1 || y0 < 1) return 0;

    static bitgrid_t blob;
    ca_blob(blob, rng, NULL, x0, y0, bw, bh);
    int count = bitgrid_count(blob);
    if (count < 4) return 0;

    for (int y = 0; y < DROWS; y++) {
        for (int x = 0; x < DCOLS; x++) {
            if (!blob[y][x]) continue;
            g[y][x].terrain = T_FLOOR;
            g[y][x].room_id = room_id;
            g[y][x].flags |= F_IN_ROOM;
        }
    }
    return 1;
}

static int carve_cave(grid_t g, rng_t *rng, int cx, int cy, uint8_t room_id) {
    int bw = rng_range(rng, 6, 9);
    int bh = rng_range(rng, 4, 6);
    return carve_ca_blob(g, rng, cx, cy, bw, bh, room_id);
}

static int carve_cavern(grid_t g, rng_t *rng, int cx, int cy, uint8_t room_id) {
    int bw = rng_range(rng, 18, 26);
    int bh = rng_range(rng, 10, 14);
    return carve_ca_blob(g, rng, cx, cy, bw, bh, room_id);
}

static int carve_entrance(grid_t g, rng_t *rng, int cx, int cy, uint8_t room_id) {
    (void)rng;
    int w = 5, h = 4;
    int x = cx - w / 2, y = cy - h / 2;
    if (x < 1 || y < 1 || x + w >= DCOLS - 1 || y + h >= DROWS - 1) return 0;
    grid_draw_rect(g, x, y, w, h, T_FLOOR, room_id);
    return 1;
}

int room_carve(grid_t g, room_type_t type, rng_t *rng, int cx, int cy, uint8_t room_id) {
    switch (type) {
        case ROOM_SMALL_RECT: return carve_small_rect(g, rng, cx, cy, room_id);
        case ROOM_CROSS:      return carve_cross(g, rng, cx, cy, room_id);
        case ROOM_SYM_CROSS:  return carve_sym_cross(g, rng, cx, cy, room_id);
        case ROOM_CIRCULAR:   return carve_circular(g, rng, cx, cy, room_id);
        case ROOM_CHUNKY:     return carve_chunky(g, rng, cx, cy, room_id);
        case ROOM_CAVE:       return carve_cave(g, rng, cx, cy, room_id);
        case ROOM_CAVERN:     return carve_cavern(g, rng, cx, cy, room_id);
        case ROOM_ENTRANCE:   return carve_entrance(g, rng, cx, cy, room_id);
        default: return 0;
    }
}

const char *room_type_name(room_type_t t) {
    switch (t) {
        case ROOM_SMALL_RECT: return "small_rect";
        case ROOM_CROSS:      return "cross";
        case ROOM_SYM_CROSS:  return "sym_cross";
        case ROOM_CIRCULAR:   return "circular";
        case ROOM_CHUNKY:     return "chunky";
        case ROOM_CAVE:       return "cave";
        case ROOM_CAVERN:     return "cavern";
        case ROOM_ENTRANCE:   return "entrance";
        default: return "?";
    }
}
