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

// DARKOP LANGUAGE SYMBOLS
static const char* DARKOP_SYMBOLS[256] = {
    "⚫0⚫", "⚫1⚫", "⚫2⚫", "⚫3⚫", "⚫4⚫", "⚫5⚫", "⚫6⚫", "⚫7⚫",
    "⚫8⚫", "⚫9⚫", "⚫A⚫", "⚫B⚫", "⚫C⚫", "⚫D⚫", "⚫E⚫", "⚫F⚫",
    "🔴0🔴", "🔴1🔴", "🔴2🔴", "🔴3🔴", "🔴4🔴", "🔴5🔴", "🔴6🔴", "🔴7🔴",
    "🔴8🔴", "🔴9🔴", "🔴A🔴", "🔴B🔴", "🔴C🔴", "🔴D🔴", "🔴E🔴", "🔴F🔴",
    "🔵0🔵", "🔵1🔵", "🔵2🔵", "🔵3🔵", "🔵4🔵", "🔵5🔵", "🔵6🔵", "🔵7🔵",
    "🔵8🔵", "🔵9🔵", "🔵A🔵", "🔵B🔵", "🔵C🔵", "🔵D🔵", "🔵E🔵", "🔵F🔵",
    "🟢0🟢", "🟢1🟢", "🟢2🟢", "🟢3🟢", "🟢4🟢", "🟢5🟢", "🟢6🟢", "🟢7🟢",
    "🟢8🟢", "🟢9🟢", "🟢A🟢", "🟢B🟢", "🟢C🟢", "🟢D🟢", "🟢E🟢", "🟢F🟢",
    "🟣0🟣", "🟣1🟣", "🟣2🟣", "🟣3🟣", "🟣4🟣", "🟣5🟣", "🟣6🟣", "🟣7🟣",
    "🟣8🟣", "🟣9🟣", "🟣A🟣", "🟣B🟣", "🟣C🟣", "🟣D🟣", "🟣E🟣", "🟣F🟣",
    "🟡0🟡", "🟡1🟡", "🟡2🟡", "🟡3🟡", "🟡4🟡", "🟡5🟡", "🟡6🟡", "🟡7🟡",
    "🟡8🟡", "🟡9🟡", "🟡A🟡", "🟡B🟡", "🟡C🟡", "🟡D🟡", "🟡E🟡", "🟡F🟡",
    "🟠0🟠", "🟠1🟠", "🟠2🟠", "🟠3🟠", "🟠4🟠", "🟠5🟠", "🟠6🟠", "🟠7🟠",
    "🟠8🟠", "🟠9🟠", "🟠A🟠", "🟠B🟠", "🟠C🟠", "🟠D🟠", "🟠E🟠", "🟠F🟠",
    "🟤0🟤", "🟤1🟤", "🟤2🟤", "🟤3🟤", "🟤4🟤", "🟤5🟤", "🟤6🟤", "🟤7🟤",
    "🟤8🟤", "🟤9🟤", "🟤A🟤", "🟤B🟤", "🟤C🟤", "🟤D🟤", "🟤E🟤", "🟤F🟤",
    "💀0💀", "💀1💀", "💀2💀", "💀3💀", "💀4💀", "💀5💀", "💀6💀", "💀7💀",
    "💀8💀", "💀9💀", "💀A💀", "💀B💀", "💀C💀", "💀D💀", "💀E💀", "💀F💀",
    "👁️0👁️", "👁️1👁️", "👁️2👁️", "👁️3👁️", "👁️4👁️", "👁️5👁️", "👁️6👁️", "👁️7👁️",
    "👁️8👁️", "👁️9👁️", "👁️A👁️", "👁️B👁️", "👁️C👁️", "👁️D👁️", "👁️E👁️", "👁️F👁️",
    "🕶️0🕶️", "🕶️1🕶️", "🕶️2🕶️", "🕶️3🕶️", "🕶️4🕶️", "🕶️5🕶️", "🕶️6🕶️", "🕶️7🕶️",
    "🕶️8🕶️", "🕶️9🕶️", "🕶️A🕶️", "🕶️B🕶️", "🕶️C🕶️", "🕶️D🕶️", "🕶️E🕶️", "🕶️F🕶️",
    "🔑0🔑", "🔑1🔑", "🔑2🔑", "🔑3🔑", "🔑4🔑", "🔑5🔑", "🔑6🔑", "🔑7🔑",
    "🔑8🔑", "🔑9🔑", "🔑A🔑", "🔑B🔑", "🔑C🔑", "🔑D🔑", "🔑E🔑", "🔑F🔑",
    "🗝️0🗝️", "🗝️1🗝️", "🗝️2🗝️", "🗝️3🗝️", "🗝️4🗝️", "🗝️5🗝️", "🗝️6🗝️", "🗝️7🗝️",
    "🗝️8🗝️", "🗝️9🗝️", "🗝️A🗝️", "🗝️B🗝️", "🗝️C🗝️", "🗝️D🗝️", "🗝️E🗝️", "🗝️F🗝️",
    "🛡️0🛡️", "🛡️1🛡️", "🛡️2🛡️", "🛡️3🛡️", "🛡️4🛡️", "🛡️5🛡️", "🛡️6🛡️", "🛡️7🛡️",
    "🛡️8🛡️", "🛡️9🛡️", "🛡️A🛡️", "🛡️B🛡️", "🛡️C🛡️", "🛡️D🛡️", "🛡️E🛡️", "🛡️F🛡️",
    "⚔️0⚔️", "⚔️1⚔️", "⚔️2⚔️", "⚔️3⚔️", "⚔️4⚔️", "⚔️5⚔️", "⚔️6⚔️", "⚔️7⚔️",
    "⚔️8⚔️", "⚔️9⚔️", "⚔️A⚔️", "⚔️B⚔️", "⚔️C⚔️", "⚔️D⚔️", "⚔️E⚔️", "⚔️F⚔️",
    "🔗0🔗", "🔗1🔗", "🔗2🔗", "🔗3🔗", "🔗4🔗", "🔗5🔗", "🔗6🔗", "🔗7🔗",
    "🔗8🔗", "🔗9🔗", "🔗A🔗", "🔗B🔗", "🔗C🔗", "🔗D🔗", "🔗E🔗", "🔗F🔗"
};

static const char DARKOP_SEPARATOR[] = "⛓️";
static const char DARKOP_HEADER[] = "DARKOP🔒V1";

static int darkop_symbol_to_byte(const char* symbol) {
    for (int i = 0; i < 256; i++) {
        if (strcmp(symbol, DARKOP_SYMBOLS[i]) == 0)
            return i;
    }
    return -1;
}

static PyObject* darkop_encrypt(PyObject* self, PyObject* args) {
    const char* python_code;
    Py_ssize_t code_len;
    
    if (!PyArg_ParseTuple(args, "s#", &python_code, &code_len))
        return NULL;

    uLongf compressed_len = compressBound(code_len);
    Bytef* compressed = malloc(compressed_len);
    if (!compressed) {
        PyErr_NoMemory();
        return NULL;
    }

    int ret = compress2(compressed, &compressed_len, (Bytef*)python_code, code_len, Z_BEST_COMPRESSION);
    if (ret != Z_OK) {
        free(compressed);
        PyErr_SetString(PyExc_RuntimeError, "Compression failed");
        return NULL;
    }

    size_t encrypted_size = strlen(DARKOP_HEADER) + strlen(DARKOP_SEPARATOR);
    for (size_t i = 0; i < compressed_len; i++) {
        encrypted_size += strlen(DARKOP_SYMBOLS[compressed[i]]) + strlen(DARKOP_SEPARATOR);
    }

    char* encrypted = malloc(encrypted_size + 1);
    if (!encrypted) {
        free(compressed);
        PyErr_NoMemory();
        return NULL;
    }

    char* ptr = encrypted;
    strcpy(ptr, DARKOP_HEADER);
    ptr += strlen(DARKOP_HEADER);
    strcpy(ptr, DARKOP_SEPARATOR);
    ptr += strlen(DARKOP_SEPARATOR);

    for (size_t i = 0; i < compressed_len; i++) {
        const char* symbol = DARKOP_SYMBOLS[compressed[i]];
        strcpy(ptr, symbol);
        ptr += strlen(symbol);
        strcpy(ptr, DARKOP_SEPARATOR);
        ptr += strlen(DARKOP_SEPARATOR);
    }
    *ptr = '\0';

    PyObject* result = PyUnicode_FromString(encrypted);
    free(compressed);
    free(encrypted);
    return result;
}

static PyObject* darkop_run(PyObject* self, PyObject* args) {
    const char* encrypted;
    if (!PyArg_ParseTuple(args, "s", &encrypted))
        return NULL;

    size_t header_len = strlen(DARKOP_HEADER);
    size_t sep_len = strlen(DARKOP_SEPARATOR);
    
    if (strncmp(encrypted, DARKOP_HEADER, header_len) != 0) {
        PyErr_SetString(PyExc_ValueError, "Invalid DARKOP encrypted data");
        return NULL;
    }

    const char* ptr = encrypted + header_len + sep_len;
    size_t symbol_count = 0;
    const char* temp_ptr = ptr;
    while (*temp_ptr) {
        const char* next_sep = strstr(temp_ptr, DARKOP_SEPARATOR);
        if (!next_sep) break;
        symbol_count++;
        temp_ptr = next_sep + sep_len;
    }

    Bytef* compressed = malloc(symbol_count);
    if (!compressed) {
        PyErr_NoMemory();
        return NULL;
    }

    size_t byte_idx = 0;
    while (*ptr && byte_idx < symbol_count) {
        const char* next_sep = strstr(ptr, DARKOP_SEPARATOR);
        if (!next_sep) break;

        size_t symbol_len = next_sep - ptr;
        char* symbol = malloc(symbol_len + 1);
        if (!symbol) {
            free(compressed);
            PyErr_NoMemory();
            return NULL;
        }
        
        strncpy(symbol, ptr, symbol_len);
        symbol[symbol_len] = '\0';

        int byte_val = darkop_symbol_to_byte(symbol);
        free(symbol);

        if (byte_val < 0) {
            free(compressed);
            PyErr_SetString(PyExc_ValueError, "Invalid DARKOP symbol");
            return NULL;
        }

        compressed[byte_idx++] = (Bytef)byte_val;
        ptr = next_sep + sep_len;
    }

    uLongf decompressed_len = byte_idx * 100;
    Bytef* decompressed = NULL;
    int uncompress_ret;
    
    for (int multiplier = 100; multiplier <= 10000; multiplier *= 10) {
        decompressed_len = byte_idx * multiplier;
        decompressed = realloc(decompressed, decompressed_len);
        
        if (!decompressed) {
            free(compressed);
            PyErr_NoMemory();
            return NULL;
        }

        uncompress_ret = uncompress(decompressed, &decompressed_len, compressed, byte_idx);
        if (uncompress_ret == Z_OK) break;
        if (uncompress_ret != Z_BUF_ERROR) {
            free(compressed);
            free(decompressed);
            PyErr_SetString(PyExc_RuntimeError, "Decompression failed");
            return NULL;
        }
    }

    free(compressed);
    if (uncompress_ret != Z_OK) {
        free(decompressed);
        PyErr_SetString(PyExc_RuntimeError, "Decompression error");
        return NULL;
    }

    char* python_code = malloc(decompressed_len + 1);
    if (!python_code) {
        free(decompressed);
        PyErr_NoMemory();
        return NULL;
    }
    
    memcpy(python_code, decompressed, decompressed_len);
    python_code[decompressed_len] = '\0';
    free(decompressed);
    PyRun_SimpleString(python_code);
    free(python_code);
    Py_RETURN_NONE;
}

static PyObject* darkop_create(PyObject* self, PyObject* args) {
    const char* input_file;
    const char* output_file;
    if (!PyArg_ParseTuple(args, "ss", &input_file, &output_file))
        return NULL;

    FILE* f = fopen(input_file, "rb");
    if (!f) {
        PyErr_SetString(PyExc_IOError, "Cannot open input file");
        return NULL;
    }
    
    fseek(f, 0, SEEK_END);
    long file_size = ftell(f);
    fseek(f, 0, SEEK_SET);
    
    char* code = malloc(file_size + 1);
    if (!code) {
        fclose(f);
        PyErr_NoMemory();
        return NULL;
    }
    
    fread(code, 1, file_size, f);
    code[file_size] = '\0';
    fclose(f);

    PyObject* encrypted_obj = darkop_encrypt(self, Py_BuildValue("(s#)", code, file_size));
    free(code);
    
    if (!encrypted_obj) return NULL;
    
    const char* encrypted = PyUnicode_AsUTF8(encrypted_obj);
    if (!encrypted) {
        Py_DECREF(encrypted_obj);
        return NULL;
    }

    FILE* out_f = fopen(output_file, "w");
    if (!out_f) {
        Py_DECREF(encrypted_obj);
        PyErr_SetString(PyExc_IOError, "Cannot create output file");
        return NULL;
    }
    
    fprintf(out_f, "#!/usr/bin/env python3\n");
    fprintf(out_f, "# DARKOP Encrypted Application\n");
    fprintf(out_f, "from darkop import run\n\n");
    fprintf(out_f, "darkop_code = \"\"\"%s\"\"\"\n\n", encrypted);
    fprintf(out_f, "if __name__ == \"__main__\":\n");
    fprintf(out_f, "    run(darkop_code)\n");
    
    fclose(out_f);
    Py_DECREF(encrypted_obj);
    Py_RETURN_NONE;
}

static PyMethodDef DarkopMethods[] = {
    {"encrypt", darkop_encrypt, METH_VARARGS, "Encrypt Python code to DARKOP language"},
    {"run", darkop_run, METH_VARARGS, "Run DARKOP encrypted code"},
    {"create", darkop_create, METH_VARARGS, "Create encrypted Python file"},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef darkopmodule = {
    PyModuleDef_HEAD_INIT,
    "darkop",
    "DARKOP - Advanced Python Code Encryption",
    -1,
    DarkopMethods
};

PyMODINIT_FUNC PyInit_darkop(void) {
    return PyModule_Create(&darkopmodule);
}