#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <windows.h>
#include <stdlib.h>
#include <string.h>

static PyObject *mod = NULL;
static PyObject *combine_fn = NULL;
static PyObject *split_fn = NULL;

static void init_python()
{
    static int initialized = 0;
    if (initialized) return;

    Py_Initialize();

    PyRun_SimpleString("import sys; sys.path.append('.')");

    mod = PyImport_ImportModule("shamirs_secret_sharing");
    if (!mod) {
        PyErr_Print();
        abort();
    }

    combine_fn = PyObject_GetAttrString(mod, "combine_wrapper");
    split_fn   = PyObject_GetAttrString(mod, "split_wrapper");

    if (!combine_fn || !split_fn) {
        PyErr_Print();
        abort();
    }

    initialized = 1;
}

__declspec(dllexport)
char* combine_shares(const char** shares, int count)
{
    init_python();

    PyObject* list = PyList_New(count);
    for (int i = 0; i < count; i++) {
        PyList_SetItem(list, i, PyUnicode_FromString(shares[i]));
    }

    PyObject* args = PyTuple_Pack(2, list, PyLong_FromLong(count));
    PyObject* res = PyObject_CallObject(combine_fn, args);

    Py_DECREF(list);
    Py_DECREF(args);

    if (!res) {
        PyErr_Print();
        return NULL;
    }

    const char* s = PyUnicode_AsUTF8(res);
    char* out = _strdup(s);
    Py_DECREF(res);
    return out;
}

__declspec(dllexport)
char* split_secret(const char* secret, int shares, int threshold)
{
    init_python();

    PyObject* pystr = PyUnicode_FromString(secret);
    PyObject* list = PyList_New(1);
    PyList_SetItem(list, 0, pystr);

    PyObject* args = PyTuple_Pack(4,
        list,
        PyLong_FromLong(1),
        PyLong_FromLong(shares),
        PyLong_FromLong(threshold)
    );

    PyObject* res = PyObject_CallObject(split_fn, args);

    Py_DECREF(list);
    Py_DECREF(args);

    if (!res) {
        PyErr_Print();
        return NULL;
    }

    const char* s = PyUnicode_AsUTF8(res);
    char* out = _strdup(s);
    Py_DECREF(res);
    return out;
}

__declspec(dllexport)
void free_string(char* p)
{
    free(p);
}