#include "oosxl_module.h"

int check_handle(void* handle, const char* name)
{
    if (handle == NULL)
    {
        PyErr_SetString(PyExc_RuntimeError, "Invalid handle");
        return 0;
    }
    return 1;
}

// module level function
PyObject* create_document(PyObject* self, PyObject* args)
{
    DocumentHandle doc_handle = doc_create();
    if (doc_handle == NULL)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to create document");
        return NULL;
    }

    return create_document_object(doc_handle);
}

PyObject* load_document(PyObject* self, PyObject* args)
{
    const char* filename;
    if (!PyArg_ParseTuple(args, "s", &filename))
        return NULL;

    DocumentHandle doc_handle = doc_load(filename);
    if (doc_handle == NULL)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to load document");
        return NULL;
    }

    return create_document_object(doc_handle);
}

PyObject* version(PyObject* self, PyObject* args)
{
    const char* version = get_version();
    return PyUnicode_FromString(version);
}

PyObject* run_message(PyObject* self, PyObject* args)
{
    const char* msg = run_msg();
    return PyUnicode_FromString(msg);
}

PyObject* encoding_rgb(PyObject* self, PyObject* args)
{
    int red, green, blue;

    if (!PyArg_ParseTuple(args, "iii", &red, &green, &blue))
    {
        return NULL;
    }

    long result = encode_rgb(red, green, blue);
    return PyLong_FromLong(result);
}

PyObject* decoding_rgb(PyObject* self, PyObject* args)
{
    long rgb;

    if (!PyArg_ParseTuple(args, "l", &rgb))
    {
        return NULL;
    }

    int red, green, blue;
    decode_rgb(rgb, &red, &green, &blue);

    return Py_BuildValue("(iii)", red, green, blue);
}

PyObject* encoding_argb(PyObject* self, PyObject* args)
{
    int red, green, blue, alpha;

    if (!PyArg_ParseTuple(args, "iiii", &red, &green, &blue, &alpha))
    {
        return NULL;
    }

    long result = encode_argb(red, green, blue, alpha);
    return PyLong_FromLong(result);
}

PyObject* decoding_argb(PyObject* self, PyObject* args)
{
    long argb;

    if (!PyArg_ParseTuple(args, "l", &argb))
    {
        return NULL;
    }

    int red, green, blue, alpha;
    decode_argb(argb, &red, &green, &blue, &alpha);

    return Py_BuildValue("(iiii)", red, green, blue, alpha);
}

PyObject* module_a1_to_row_col(PyObject* self, PyObject* args)
{
    const char* a1;

    if (!PyArg_ParseTuple(args, "s", &a1))
    {
        return NULL;
    }

    int row, col;
    int result = a1_to_row_col(a1, &row, &col);
    if (result == 0)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to convert A1 notation");
        return NULL;
    }

    return Py_BuildValue("(ii)", row, col);
}

PyObject* module_row_col_to_a1(PyObject* self, PyObject* args)
{
    int row, col;

    if (!PyArg_ParseTuple(args, "ii", &row, &col))
    {
        return NULL;
    }

    char buffer[32];
    int result = row_col_to_a1(row, col, buffer);
    if (result == 0)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to convert row/col to A1");
        return NULL;
    }

    return PyUnicode_FromString(buffer);
}

PyObject* decoding_date(PyObject* self, PyObject* args)
{
    double date;

    if (!PyArg_ParseTuple(args, "d", &date))
    {
        return NULL;
    }

    int year, month, day;
    decode_date(date, &year, &month, &day);

    return Py_BuildValue("(iii)", year, month, day);
}

PyObject* decoding_date1904(PyObject* self, PyObject* args)
{
    double date;

    if (!PyArg_ParseTuple(args, "d", &date))
    {
        return NULL;
    }

    int year, month, day;
    decode_date1904(date, &year, &month, &day);

    return Py_BuildValue("(iii)", year, month, day);
}

PyObject* decoding_time(PyObject* self, PyObject* args)
{
    double time;

    if (!PyArg_ParseTuple(args, "d", &time))
    {
        return NULL;
    }

    int hour, minute, second, msec;
    decode_time(time, &hour, &minute, &second, &msec);

    return Py_BuildValue("(iiii)", hour, minute, second, msec);
}

PyObject* decoding_datetime(PyObject* self, PyObject* args)
{
    double datetime;

    if (!PyArg_ParseTuple(args, "d", &datetime))
    {
        return NULL;
    }

    int year, month, day, hour, minute, second, msec;
    decode_datetime(datetime, &year, &month, &day, &hour, &minute, &second, &msec);

    return Py_BuildValue("(iiiiiii)", year, month, day, hour, minute, second, msec);
}

PyObject* decoding_datetime1904(PyObject* self, PyObject* args)
{
    double datetime;

    if (!PyArg_ParseTuple(args, "d", &datetime))
    {
        return NULL;
    }

    int year, month, day, hour, minute, second, msec;
    decode_datetime1904(datetime, &year, &month, &day, &hour, &minute, &second, &msec);

    return Py_BuildValue("(iiiiiii)", year, month, day, hour, minute, second, msec);
}

PyObject* encoding_date(PyObject* self, PyObject* args)
{
    int year, month, day;

    if (!PyArg_ParseTuple(args, "iii", &year, &month, &day))
    {
        return NULL;
    }

    double result = encode_date(year, month, day);
    return PyFloat_FromDouble(result);
}

PyObject* encoding_time(PyObject* self, PyObject* args)
{
    int hour, minute, second, msec = 0;

    if (!PyArg_ParseTuple(args, "iii|i", &hour, &minute, &second, &msec))
    {
        return NULL;
    }

    double result = encode_time(hour, minute, second, msec);
    return PyFloat_FromDouble(result);
}

PyObject* encoding_datetime(PyObject* self, PyObject* args)
{
    int year, month, day, hour, minute, second, msec = 0;

    if (!PyArg_ParseTuple(args, "iiiiii|i", &year, &month, &day, &hour, &minute, &second, &msec))
    {
        return NULL;
    }

    double result = encode_datetime(year, month, day, hour, minute, second, msec);
    return PyFloat_FromDouble(result);
}

static PyMethodDef module_methods[] = {
    {"create_document", create_document, METH_VARARGS, "Create a new empty document"},
    {"load_document", load_document, METH_VARARGS, "Load document from file"},
    {"version", version, METH_NOARGS, "Get library version"},
    {"run_message", run_message, METH_NOARGS, "Get run message"},
    {"encoding_rgb", encoding_rgb, METH_VARARGS, "Encode RGB color"},
    {"decoding_rgb", decoding_rgb, METH_VARARGS, "Decode RGB color"},
    {"encoding_argb", encoding_argb, METH_VARARGS, "Encode ARGB color"},
    {"decoding_argb", decoding_argb, METH_VARARGS, "Decode ARGB color"},
    {"a1_to_rowcol", module_a1_to_row_col, METH_VARARGS, "Convert A1 notation to row/col"},
    {"rowcol_to_a1", module_row_col_to_a1, METH_VARARGS, "Convert row/col to A1 notation"},
    {"decoding_date", decoding_date, METH_VARARGS, "Decode date from Excel serial"},
    {"decoding_date1904", decoding_date1904, METH_VARARGS, "Decode date from Excel 1904 serial"},
    {"decoding_time", decoding_time, METH_VARARGS, "Decode time from Excel serial"},
    {"decoding_datetime", decoding_datetime, METH_VARARGS, "Decode datetime from Excel serial"},
    {"decoding_datetime1904", decoding_datetime1904, METH_VARARGS, "Decode datetime from Excel 1904 serial"},
    {"encoding_date", encoding_date, METH_VARARGS, "Encode date to Excel serial"},
    {"encoding_time", encoding_time, METH_VARARGS, "Encode time to Excel serial"},
    {"encoding_datetime", encoding_datetime, METH_VARARGS, "Encode datetime to Excel serial"},
    {NULL, NULL, 0, NULL} /* Sentinel */
};

struct PyModuleDef oosxl_module = {
    PyModuleDef_HEAD_INIT,
    .m_name = "oosxl",
    .m_doc = "Python binding for OOSXL library",
    .m_size = -1,
    .m_methods = module_methods,
};
