#include <fvm-c/framework.h>
#include <fvm-c/update.h>
#include <fvm-c/plot.h>
#include <fvm-c/compiler.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

// Stub implementation - all functions return dummy values
// This allows the Go webserver to compile without the real FVM library

struct fvm_framework {
    int dummy;
};

struct fvm_compiler {
    const char *api_table;
};

struct fvm_output {
    int dummy;
};

// Framework
fvm_framework_t *fvm_framework_acquire(void *config) {
    fvm_framework_t *fw = (fvm_framework_t *)calloc(1, sizeof(fvm_framework_t));
    return fw;
}

void fvm_framework_release(fvm_framework_t *fw) {
    if (fw) free(fw);
}

int fvm_update(fvm_framework_t *fw, fvm_update_t *update) {
    // Stub: always succeed
    return 1;
}

// Update
fvm_update_t *fvm_update_create(ct_string_t data) {
    fvm_update_t *u = (fvm_update_t *)calloc(1, sizeof(fvm_update_t));
    if (u) {
        u->buf.ptr = (char *)malloc(data.length);
        if (u->buf.ptr) {
            memcpy((char *)u->buf.ptr, data.ptr, data.length);
            u->buf.length = data.length;
        }
    }
    return u;
}

fvm_update_t *fvm_update_merge(fvm_update_t *base, fvm_update_t *patch) {
    // Stub: just return a copy of base
    if (!base) return NULL;
    fvm_update_t *merged = (fvm_update_t *)calloc(1, sizeof(fvm_update_t));
    if (merged && base->buf.ptr) {
        merged->buf.ptr = (char *)malloc(base->buf.length);
        if (merged->buf.ptr) {
            memcpy((char *)merged->buf.ptr, base->buf.ptr, base->buf.length);
            merged->buf.length = base->buf.length;
        }
    }
    return merged;
}

void fvm_update_destroy(fvm_update_t *update) {
    if (update) {
        if (update->buf.ptr) free((void *)update->buf.ptr);
        free(update);
    }
}

// Plot
fvm_plot_t *fvm_plot(fvm_framework_t *fw) {
    fvm_plot_t *p = (fvm_plot_t *)calloc(1, sizeof(fvm_plot_t));
    if (p) {
        const char *empty = "{}";
        p->buf.ptr = strdup(empty);
        p->buf.length = strlen(empty);
    }
    return p;
}

void fvm_plot_destroy(fvm_plot_t *plot) {
    if (plot) {
        if (plot->buf.ptr) free((void *)plot->buf.ptr);
        free(plot);
    }
}

// Dump
fvm_update_t *fvm_dump(fvm_framework_t *fw) {
    return fvm_update_create(CT_STRING_FROM_CSTR(""));
}

// Compiler
fvm_compiler_t *fvm_compiler_acquire(const char *api_table) {
    fvm_compiler_t *c = (fvm_compiler_t *)calloc(1, sizeof(fvm_compiler_t));
    if (c) c->api_table = api_table;
    return c;
}

void fvm_compiler_release(fvm_compiler_t *compiler) {
    if (compiler) free(compiler);
}

bool fvm_compiler_load_re(fvm_compiler_t *compiler, const char *re, size_t re_len) {
    return true;
}

bool fvm_compiler_dump_re(fvm_compiler_t *compiler, char **out, size_t *out_len) {
    *out = strdup("");
    *out_len = 0;
    return true;
}

fvm_output_t *fvm_compile(fvm_compiler_t *compiler, const char *text) {
    fvm_output_t *o = (fvm_output_t *)calloc(1, sizeof(fvm_output_t));
    return o;
}

fvm_output_t *fvm_serialize(fvm_output_t *output, bool diff, long base, long target) {
    fvm_output_t *o = (fvm_output_t *)calloc(1, sizeof(fvm_output_t));
    return o;
}

void fvm_output_destroy(fvm_output_t *output) {
    if (output) free(output);
}
