#include "json.h"

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int parse_int_after_label(const char *label, const char *buf, int *out) {
    const char *p = strstr(buf, label);
    if (!p) return -1;
    p = strchr(p, ':');
    if (!p) return -1;
    ++p;
    while (*p && isspace((unsigned char)*p)) ++p;
    char *endptr = NULL;
    long v = strtol(p, &endptr, 10);
    if (p == endptr) return -1;
    *out = (int)v;
    return 0;
}

static int parse_entities(const char *buf, int size, Board *out) {
    const char *p = strstr(buf, "\"entities\"");
    if (!p) return -1;
    p = strchr(p, '[');
    if (!p) return -1;

    int total = size * size;
    int idx = 0;
    while (*p && idx < total) {
        while (*p && !isdigit((unsigned char)*p) && *p != '-' && *p != '+') ++p;
        if (!*p) break;
        char *endptr = NULL;
        long v = strtol(p, &endptr, 10);
        if (p == endptr) break;
        int y = idx / size;
        int x = idx % size;
        out->cells[y][x] = (uint8_t)v;
        idx++;
        p = endptr;
    }
    return idx == total ? 0 : -1;
}

int load_puzzle(const char *path, Board *out) {
    FILE *fp = fopen(path, "rb");
    if (!fp) {
        fprintf(stderr, "Failed to open puzzle file: %s\n", path);
        return -1;
    }
    fseek(fp, 0, SEEK_END);
    long len = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    if (len <= 0 || len > 5 * 1024 * 1024) {
        fclose(fp);
        fprintf(stderr, "Puzzle file size invalid.\n");
        return -1;
    }
    char *buf = (char *)malloc((size_t)len + 1);
    if (!buf) {
        fclose(fp);
        fprintf(stderr, "Out of memory reading puzzle.\n");
        return -1;
    }
    size_t rlen = fread(buf, 1, (size_t)len, fp);
    fclose(fp);
    buf[rlen] = '\0';

    int size = 0;
    if (parse_int_after_label("\"size\"", buf, &size) != 0) {
        fprintf(stderr, "Failed to parse size.\n");
        free(buf);
        return -1;
    }
    if (size < 4 || size > MAX_SIZE || (size % 2 != 0)) {
        fprintf(stderr, "Invalid size %d (must be even and between 4 and %d).\n", size, MAX_SIZE);
        free(buf);
        return -1;
    }

    out->size = size;
    if (parse_entities(buf, size, out) != 0) {
        fprintf(stderr, "Failed to parse entities array.\n");
        free(buf);
        return -1;
    }

    out->pair_count = board_compute_pairs(out);
    free(buf);
    return 0;
}
