// Written by retoor@molodetz.nl

// This program provides functionality to highlight the keywords in source code using ANSI color formatting and convert Markdown syntax into ANSI-colored text output.

// Uses standard C libraries: <stdio.h>, <string.h>. Also utilizes ANSI escape codes for text formatting.

// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

#define RESET "\033[0m"
#define BOLD "\033[1m"
#define ITALIC "\033[3m"
#define FG_YELLOW "\033[33m"
#define FG_BLUE "\033[34m"
#define FG_CYAN "\033[36m"

int is_keyword(const char *word) {
    
const char *keywords[] = {
    "int", "float", "double", "char", "void", 
    "if", "else", "while", "for", "return", 
    "struct", "printf",
    // Rust keywords
    "let", "fn", "impl", "match", "enum", "trait", "use", "mod", "pub", "const", "static",
    // Python keywords
    "def", "class", "import", "from", "as", "with", "try", "except", "finally", "lambda", "async", "await",
    // Java keywords
    "public", "private", "protected", "class", "interface", "extends", "implements", "new", "static", "final", "synchronized",
    // JavaScript keywords
    "var", "let", "const", "function", "async", "await", "if", "else", "switch", "case", "break", "continue", "return",
    // C++ keywords
    "namespace", "template", "typename", "class", "public", "private", "protected", "virtual", "override", "friend", "new",
    // Go keywords
    "package", "import", "func", "var", "const", "type", "interface", "struct", "go", "defer", "select",
    // Bash keywords
    "if", "then", "else", "elif", "fi", "case", "esac", "for", "while", "until", "do", "done", "function",
    // C# keywords
    "namespace", "using", "class", "interface", "public", "private", "protected", "static", "void", "new", "override"
};

    for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
        if (strcmp(word, keywords[i]) == 0) {
            return 1;
        }
    }
    return 0;
}

void highlight_code(const char *code) {
    const char *ptr = code;
    char buffer[4096];
    size_t index = 0;
    
    while (*ptr) {
        if ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || (*ptr == '_')) {
            while ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || (*ptr >= '0' && *ptr <= '9') || (*ptr == '_')) {
                buffer[index++] = *ptr++;
            }
            buffer[index] = 0;

            if (is_keyword(buffer)) {
                printf(FG_BLUE "%s" RESET, buffer);
            } else {
                printf("%s", buffer);
            }
            index = 0;
        } else if (*ptr >= '0' && *ptr <= '9') {
            while (*ptr >= '0' && *ptr <= '9') {
                buffer[index++] = *ptr++;
            }
            buffer[index] = 0;
            printf(FG_CYAN "%s" RESET, buffer);
            index = 0;
        } else {
            putchar(*ptr);
            ptr++;
        }
    }
}

void parse_markdown_to_ansi(const char *markdown) {
    const char *ptr = markdown;
    bool inside_code = false;

    while (*ptr) {
        if (*ptr == '`' && *(ptr + 1) != '`') {
            inside_code = !inside_code;
            if (inside_code) {
                printf(FG_YELLOW);
            } else {
                printf(RESET);
            }
            ptr++;
            continue;
        }else if(!strncmp(ptr, "```", 3)) {
            inside_code = !inside_code;
            if(inside_code){
            ptr = strstr(ptr, "\n") + 1;
            }else{
                ptr+=3;
            }
            if(*ptr == '\0'){
               break; 
            } 
        }

        if (inside_code) {
            char code_buffer[1024*1024] = {0};;
            size_t index = 0;

            while (*ptr && *ptr != '`') {
                code_buffer[index++] = *ptr++;
                if (*ptr == '\n' || *ptr == ' ' || *ptr == '\t' || *ptr == '.') {
                    code_buffer[index++] = 0;
                    highlight_code(code_buffer);
                    index = 0;
                }
            }
            code_buffer[index] = 0;
            if (index) {
                highlight_code(code_buffer);
            }
        } else {
            if (strncmp(ptr, "**", 2) == 0) {
                printf(BOLD);
                ptr += 2;
                while (*ptr && strncmp(ptr, "**", 2) != 0) {
                    putchar(*ptr++);
                }
                if (*ptr == '*' && *(ptr + 1) == '*') ptr += 2;
                printf(RESET);
            } else if (*ptr == '*' && (ptr == markdown || *(ptr - 1) != '*')) {
                printf(ITALIC);
                ptr++;
                while (*ptr && *ptr != '*') {
                    putchar(*ptr++);
                }
                if (*ptr == '*') ptr++;
                printf(RESET);
            } else if (strncmp(ptr, "### ", 4) == 0) {
                printf(BOLD FG_YELLOW);
                ptr += 4;
                while (*ptr && *ptr != '\n') {
                    putchar(*ptr++);
                }
                printf(RESET "\n");
            } else if (strncmp(ptr, "## ", 3) == 0) {
                printf(BOLD FG_YELLOW);
                ptr += 3;
                while (*ptr && *ptr != '\n') {
                    putchar(*ptr++);
                }
                printf(RESET "\n");
            } else if (strncmp(ptr, "# ", 2) == 0) {
                printf(BOLD FG_YELLOW);
                ptr += 2;
                while (*ptr && *ptr != '\n') {
                    putchar(*ptr++);
                }
                printf(RESET "\n");
            } else {
                putchar(*ptr);
                ptr++;
            }
        }
    }
}