#include "dijkstra.h"
#include <stddef.h>

static int passable(uint8_t t) {
    return t == T_FLOOR || t == T_CORRIDOR || t == T_DOOR || t == T_BRIDGE
        || t == T_STAIRS_UP || t == T_STAIRS_DOWN;
}

void bfs_from(grid_t g, int sx, int sy, dist_map_t dist,
              int extra_passable_x, int extra_passable_y) {
    for (int y = 0; y < DROWS; y++)
        for (int x = 0; x < DCOLS; x++)
            dist[y][x] = DIST_UNREACHABLE;

    if (!grid_in_bounds(sx, sy)) return;

    static const int dx4[4] = {1, -1, 0, 0};
    static const int dy4[4] = {0, 0, 1, -1};

    int qx[DCOLS * DROWS];
    int qy[DCOLS * DROWS];
    int head = 0, tail = 0;

    dist[sy][sx] = 0;
    qx[tail] = sx; qy[tail] = sy; tail++;

    while (head < tail) {
        int cx = qx[head], cy = qy[head]; head++;
        int16_t d = dist[cy][cx];
        for (int i = 0; i < 4; i++) {
            int nx = cx + dx4[i], ny = cy + dy4[i];
            if (!grid_in_bounds(nx, ny)) continue;
            int is_extra = (nx == extra_passable_x && ny == extra_passable_y);
            if (!is_extra && !passable(g[ny][nx].terrain)) continue;
            if (dist[ny][nx] <= d + 1) continue;
            dist[ny][nx] = d + 1;
            qx[tail] = nx; qy[tail] = ny; tail++;
        }
    }
}

int is_connected(grid_t g, int *out_unreached) {
    int sx = -1, sy = -1, total = 0;
    for (int y = 0; y < DROWS; y++) {
        for (int x = 0; x < DCOLS; x++) {
            if (passable(g[y][x].terrain)) {
                if (sx < 0) { sx = x; sy = y; }
                total++;
            }
        }
    }
    if (total == 0) { if (out_unreached) *out_unreached = 0; return 1; }

    static dist_map_t dist;
    bfs_from(g, sx, sy, dist, -1, -1);
    int reached = 0;
    for (int y = 0; y < DROWS; y++)
        for (int x = 0; x < DCOLS; x++)
            if (passable(g[y][x].terrain) && dist[y][x] != DIST_UNREACHABLE)
                reached++;
    if (out_unreached) *out_unreached = total - reached;
    return reached == total;
}
