#include "oosxl_module.h"


PyTypeObject WorkbookType;

static void Workbook_dealloc(WorkbookObject* self)
{
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject* Workbook_is_date1904(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    int result = wb_is_date1904(self->handle);
    return PyBool_FromLong(result);
}

static PyObject* Workbook_set_date1904(WorkbookObject* self, PyObject* args)
{
    int set = 1;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "|p", &set))
    {
        return NULL;
    }

    wb_set_date1904(self->handle, set);
    Py_RETURN_NONE;
}

static PyObject* Workbook_is_a1_ref_mode(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    int result = wb_is_a1_ref_mode(self->handle);
    return PyBool_FromLong(result);
}

static PyObject* Workbook_set_a1_ref_mode(WorkbookObject* self, PyObject* args)
{
    int mode = 1;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "|p", &mode))
    {
        return NULL;
    }

    wb_set_a1_ref_mode(self->handle, mode);
    Py_RETURN_NONE;
}

static PyObject* Workbook_get_calc_mode(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    int result = wb_get_calc_mode(self->handle);
    return PyLong_FromLong(result);
}

static PyObject* Workbook_set_calc_mode(WorkbookObject* self, PyObject* args)
{
    int calc_type;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "i", &calc_type))
    {
        return NULL;
    }

    wb_set_calc_mode(self->handle, calc_type);
    Py_RETURN_NONE;
}

static PyObject* Workbook_add_worksheet(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    const char* name = NULL;
    if (!PyArg_ParseTuple(args, "|z", &name))
        return NULL;

    WorksheetHandle ws_handle = wb_add_worksheet(self->handle, name);
    if (ws_handle == NULL)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to add worksheet");
        return NULL;
    }

    return create_worksheet_object(ws_handle);
}

static PyObject* Workbook_insert_worksheet(WorkbookObject* self, PyObject* args)
{
    int index;
    const char* name = NULL;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "i|z", &index, &name))
        return NULL;

    WorksheetHandle ws_handle = wb_insert_worksheet(self->handle, index, name);
    if (ws_handle == NULL)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to insert worksheet");
        return NULL;
    }

    return create_worksheet_object(ws_handle);
}

static PyObject* Workbook_shift_sheet(WorkbookObject* self, PyObject* args)
{
    int src_index, dst_index;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "ii", &src_index, &dst_index))
    {
        return NULL;
    }

    wb_shift_sheet(self->handle, src_index, dst_index);
    Py_RETURN_NONE;
}

static PyObject* Workbook_delete_sheet(WorkbookObject* self, PyObject* args)
{
    int index;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "i", &index))
    {
        return NULL;
    }

    wb_delete_sheet(self->handle, index);
    Py_RETURN_NONE;
}

static PyObject* Workbook_sheet_count(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    int count = wb_sheet_count(self->handle);
    return PyLong_FromLong(count);
}

static PyObject* Workbook_get_sheet(WorkbookObject* self, PyObject* args)
{
    int index;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "i", &index))
    {
        return NULL;
    }

    WorksheetHandle ws_handle = wb_get_sheet(self->handle, index);
    if (ws_handle == NULL)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to get worksheet");
        return NULL;
    }

    return create_worksheet_object(ws_handle);
}

static PyObject* Workbook_sheet_type(WorkbookObject* self, PyObject* args)
{
    int index;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "i", &index))
    {
        return NULL;
    }

    int result = wb_sheet_type(self->handle, index);
    return PyLong_FromLong(result);
}

static PyObject* Workbook_get_sheet_state(WorkbookObject* self, PyObject* args)
{
    int index;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "i", &index))
    {
        return NULL;
    }

    int result = wb_get_sheet_state(self->handle, index);
    return PyLong_FromLong(result);
}

static PyObject* Workbook_set_sheet_state(WorkbookObject* self, PyObject* args)
{
    int index, state;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "ii", &index, &state))
    {
        return NULL;
    }

    wb_set_sheet_state(self->handle, index, state);
    Py_RETURN_NONE;
}

static PyObject* Workbook_sheet_name(WorkbookObject* self, PyObject* args)
{
    int index;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "i", &index))
    {
        return NULL;
    }

    const char* result = wb_sheet_name(self->handle, index);
    if (result == NULL)
    {
        Py_RETURN_NONE;
    }

    return PyUnicode_FromString(result);
}

static PyObject* Workbook_rename_sheet(WorkbookObject* self, PyObject* args)
{
    int index;
    const char* newname;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "is", &index, &newname))
    {
        return NULL;
    }

    wb_rename_sheet(self->handle, index, newname);
    Py_RETURN_NONE;
}

static PyObject* Workbook_get_active_sheet(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    int index = wb_get_active_sheet(self->handle);
    return PyLong_FromLong(index);
}

static PyObject* Workbook_set_active_sheet(WorkbookObject* self, PyObject* args)
{
    int index;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "i", &index))
    {
        return NULL;
    }

    int result = wb_set_active_sheet(self->handle, index);
    if (result == 0)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to set active sheet");
        return NULL;
    }

    Py_RETURN_NONE;
}

static PyObject* Workbook_set_defined_name(WorkbookObject* self, PyObject* args)
{
    const char *name, *expr, *local_name = NULL;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "ss|z", &name, &expr, &local_name))
    {
        return NULL;
    }

    int result = wb_set_defined_name(self->handle, name, expr, local_name);
    if (result == 0)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to set defined name");
        return NULL;
    }

    Py_RETURN_NONE;
}

static PyObject* Workbook_defined_name_num(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    int result = wb_defined_name_num(self->handle);
    return PyLong_FromLong(result);
}

static PyObject* Workbook_get_defined_name(WorkbookObject* self, PyObject* args)
{
    int index;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "i", &index))
        return NULL;

    int local = 0;
    const char* name = wb_get_defined_name(self->handle, index, &local);
    if (name == NULL)
    {
        Py_RETURN_NONE;
    }

    const char* local_name = NULL;
    if (local)
        local_name = wb_get_local_name(self->handle, index);

    const char* expr = wb_get_defined_name_expr(self->handle, index);

    return Py_BuildValue("(s s s)", name, local, expr);
}

static PyObject* Workbook_delete_defined_name(WorkbookObject* self, PyObject* args)
{
    int index;

    if (!check_handle(self->handle, "workbook"))
        return NULL;

    if (!PyArg_ParseTuple(args, "i", &index))
        return NULL;

    wb_delete_defined_name(self->handle, index);

    Py_RETURN_NONE;
}

static PyObject* Workbook_get_named_style(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    const char* name;
    if (!PyArg_ParseTuple(args, "s", &name))
        return NULL;

    StyleHandle style_handle = wb_get_named_style(self->handle, name);
    if (style_handle == NULL)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to get named style");
        return NULL;
    }

    return create_style_object(style_handle);
}

static PyObject* Workbook_add_custom_style(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    const char* name;
    PyObject* style_obj;

    if (!PyArg_ParseTuple(args, "sO", &name, &style_obj))
        return NULL;

    if (!PyObject_TypeCheck(style_obj, &StyleType))
    {
        PyErr_SetString(PyExc_TypeError, "Expected a Style object");
        return NULL;
    }

    StyleObject* style = (StyleObject*)style_obj;
    StyleHandle style_handle = wb_add_custom_style(self->handle, name, style->handle);
    if (style_handle == NULL)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to add custom style");
        return NULL;
    }

    return create_style_object(style_handle);
}

static PyObject* Workbook_modify_named_style(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    const char* name;
    PyObject* style_obj;

    if (!PyArg_ParseTuple(args, "sO", &name, &style_obj))
    {
        return NULL;
    }

    if (!PyObject_TypeCheck(style_obj, &StyleType))
    {
        PyErr_SetString(PyExc_TypeError, "Expected a Style object");
        return NULL;
    }

    StyleObject* style = (StyleObject*)style_obj;
    int result = wb_modify_named_style(self->handle, name, style->handle);
    if (result == 0)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to modify named style");
        return NULL;
    }

    Py_RETURN_NONE;
}

static PyObject* Workbook_make_normal_style(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    StyleHandle style_handle = wb_make_normal_style(self->handle);
    if (style_handle == NULL)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to create normal style");
        return NULL;
    }

    return create_style_object(style_handle);
}

static PyObject* Workbook_make_richtext(WorkbookObject* self, PyObject* args)
{
    if (!check_handle(self->handle, "workbook"))
        return NULL;

    RichtextHandle rt_handle = wb_make_richtext(self->handle);
    if (rt_handle == NULL)
    {
        PyErr_SetString(PyExc_RuntimeError, "Failed to create richtext");
        return NULL;
    }

    return create_richtext_object(rt_handle);
}

static PyMethodDef Workbook_methods[] = {
    {"is_date1904", (PyCFunction)Workbook_is_date1904, METH_NOARGS, "Check if using 1904 date system"},
    {"set_date1904", (PyCFunction)Workbook_set_date1904, METH_VARARGS, "Set 1904 date system(default: True)"},

    {"is_a1_ref_mode", (PyCFunction)Workbook_is_a1_ref_mode, METH_NOARGS, "Check if using A1 reference mode"},
    {"set_a1_ref_mode", (PyCFunction)Workbook_set_a1_ref_mode, METH_VARARGS, "Set A1 reference mode(default: True)"},

    {"get_calc_mode", (PyCFunction)Workbook_get_calc_mode, METH_NOARGS, "Get calculation mode"},
    {"set_calc_mode", (PyCFunction)Workbook_set_calc_mode, METH_VARARGS, "Set calculation mode"},

    {"add_worksheet", (PyCFunction)Workbook_add_worksheet, METH_VARARGS, "Add a new worksheet(optional worksheet name)"},
    {"insert_worksheet", (PyCFunction)Workbook_insert_worksheet, METH_VARARGS, "Insert worksheet at index(optional worksheet name)"},
    {"shift_sheet", (PyCFunction)Workbook_shift_sheet, METH_VARARGS, "Move sheet position"},
    {"delete_sheet", (PyCFunction)Workbook_delete_sheet, METH_VARARGS, "Delete sheet"},
    {"sheet_count", (PyCFunction)Workbook_sheet_count, METH_NOARGS, "Get number of worksheets"},
    {"get_sheet", (PyCFunction)Workbook_get_sheet, METH_VARARGS, "Get worksheet by index"},
    {"sheet_type", (PyCFunction)Workbook_sheet_type, METH_VARARGS, "Get sheet type"},
    {"get_sheet_state", (PyCFunction)Workbook_get_sheet_state, METH_VARARGS, "Get sheet state"},
    {"set_sheet_state", (PyCFunction)Workbook_set_sheet_state, METH_VARARGS, "Set sheet state"},
    {"sheet_name", (PyCFunction)Workbook_sheet_name, METH_VARARGS, "Get sheet name"},
    {"rename_sheet", (PyCFunction)Workbook_rename_sheet, METH_VARARGS, "Rename sheet"},

    {"get_active_sheet", (PyCFunction)Workbook_get_active_sheet, METH_NOARGS, "Get active sheet index"},
    {"set_active_sheet", (PyCFunction)Workbook_set_active_sheet, METH_VARARGS, "Set active sheet"},

    {"set_defined_name", (PyCFunction)Workbook_set_defined_name, METH_VARARGS, "Set defined name(optional local name)"},
    {"defined_name_num", (PyCFunction)Workbook_defined_name_num, METH_VARARGS, "Get number of defined names"},
    {"get_defined_name", (PyCFunction)Workbook_get_defined_name, METH_VARARGS, "Get defined name"},
    {"delete_defined_name", (PyCFunction)Workbook_delete_defined_name, METH_VARARGS, "Delete defined name"},

    {"get_named_style", (PyCFunction)Workbook_get_named_style, METH_VARARGS, "Get named style"},
    {"add_custom_style", (PyCFunction)Workbook_add_custom_style, METH_VARARGS, "Add custom style"},
    {"modify_named_style", (PyCFunction)Workbook_modify_named_style, METH_VARARGS, "Modify named style"},
    {"make_normal_style", (PyCFunction)Workbook_make_normal_style, METH_NOARGS, "Create a normal style"},
    {"make_richtext", (PyCFunction)Workbook_make_richtext, METH_NOARGS, "Create a richtext object"},

    {NULL} /* Sentinel */
};

PyTypeObject WorkbookType = {
    PyVarObject_HEAD_INIT(NULL, 0)
        .tp_name = "oosxl.Workbook",
    .tp_doc = "Workbook object",
    .tp_basicsize = sizeof(WorkbookObject),
    .tp_itemsize = 0,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_new = PyType_GenericNew,
    .tp_dealloc = (destructor)Workbook_dealloc,
    .tp_methods = Workbook_methods,
};

PyObject* create_workbook_object(WorkbookHandle handle)
{
    WorkbookObject* obj = (WorkbookObject*)PyObject_New(WorkbookObject, &WorkbookType);
    if (obj != NULL)
    {
        obj->handle = handle;
    }
    return (PyObject*)obj;
}
