#include "../../include/articles_p/process_md.h"

int process_md(article_info article, char **out)
{
    *out = malloc(1);
    (*out)[0] = '\0';
    char *rest = strdup(article.content), *free_rest = rest;
    char *buff;

    int is_in_code = 0;
    int is_in_list = 0;

    while ((buff = strtok_r(rest, "\n", &rest)) != NULL)
    {
        if (strncmp(buff, "```", 3) == 0)
        {
            char *snippet;

            if (is_in_code)
            {
                snippet = "</pre></code>\n";
                is_in_code = 0;
            }
            else
            {
                snippet = "<pre><code>";
                is_in_code = 1;
            }

            char *tmp_out = realloc(*out, strlen(*out) + strlen(snippet) + 1);
            if (tmp_out == NULL)
            {
                perror("Couldn't allocate memory for new element");
                continue;
            }
            *out = tmp_out;
            strcat(*out, snippet);

            continue;
        }

        if (is_in_code)
        {
            char *tmp_out = realloc(*out, strlen(*out) + strlen(buff) + strlen("<br/>") + 1);
            if (tmp_out == NULL)
            {
                perror("Couldn't allocate memory for new element");
                continue;
            }
            *out = tmp_out;

            strcat(*out, buff);
            strcat(*out, "<br/>");

            continue;
        }

        if ((buff[0] == '*' && buff[1] == ' ') || (buff[0] == '-' && buff[1] == ' ') || (buff[0] == '+' && buff[1] == ' '))
        {
            char *begining = "";
            if (!is_in_list)
            {
                begining = "<ul>\n";
                is_in_list = 1;
            }

            memmove(buff, buff + 2, strlen(buff) - 1);

            size_t append_line_length = snprintf(NULL, 0, "%s<li>%s</li>\n", begining, buff) + 1;
            char *append = malloc(append_line_length);
            char *tmp_out = realloc(*out, strlen(*out) + append_line_length);
            if (append == NULL || tmp_out == NULL)
            {
                perror("Couldn't allocate memory for new element");
                continue;
            }
            *out = tmp_out;

            snprintf(append, append_line_length, "%s<li>%s</li>\n", begining, buff);
            strcat(*out, append);

            free(append);
            continue;
        }

        if (is_in_list)
        {
            char *tmp_out = realloc(*out, strlen(*out) + strlen("</ul>\n") + 1);
            if (tmp_out == NULL)
            {
                perror("Couldn't allocate memory for new element");
                continue;
            }
            *out = tmp_out;
            strcat(*out, "</ul>\n");
            is_in_list = 0;
        }

        if (strcmp(buff, "***") == 0)
        {
            char *tmp_out = realloc(*out, strlen(*out) + strlen("<hr>\n") + 1);
            if (tmp_out == NULL)
            {
                perror("Couldn't allocate memory for new element");
                continue;
            }
            *out = tmp_out;
            strcat(*out, "<hr>\n");
            continue;
        }

        if (buff[0] == '#')
        {
            int n = 1;
            while (buff[n] == '#')
                n++;
            int k = (n > 6) ? 6 : n;

            memmove(buff, buff + n + 1, strlen(buff) - (n + 1) + 1); // n + 1 is to remove space after #

            size_t append_line_length = snprintf(NULL, 0, "<h%d>%s</h%d>\n", k, buff, k) + 1;
            char *append = malloc(append_line_length);
            char *tmp_out = realloc(*out, strlen(*out) + append_line_length);
            if (append == NULL || tmp_out == NULL)
            {
                perror("Couldn't allocate memory for new element");
                continue;
            }
            *out = tmp_out;

            snprintf(append, append_line_length, "<h%d>%s</h%d>\n", k, buff, k);
            strcat(*out, append);

            free(append);
            continue;
        }

        if (buff[0] == '>')
        {
            memmove(buff, buff + 2, strlen(buff) - 1);

            size_t append_line_length = snprintf(NULL, 0, "<blockquote>%s</blockquote>\n", buff) + 1;
            char *append = malloc(append_line_length);
            char *tmp_out = realloc(*out, strlen(*out) + append_line_length);
            if (append == NULL || tmp_out == NULL)
            {
                perror("Couldn't allocate memory for new element");
                continue;
            }
            *out = tmp_out;

            snprintf(append, append_line_length, "<blockquote>%s</blockquote>\n", buff);
            strcat(*out, append);

            free(append);
            continue;
        }

        char *tmp_out = realloc(*out, strlen(*out) + strlen("<p>") + 1);
        if (tmp_out == NULL)
        {
            perror("Couldn't allocate memory for new element");
            continue;
        }
        *out = tmp_out;

        strcat(*out, "<p>");

        for (int i = 0; i < strlen(buff); i++)
        {
            if (buff[i] == '*' && buff[i - 1] != '\\' && buff[i + 1] != ' ')
            {
                int n = 1;
                while (buff[i + n] == '*')
                    n++;

                char *tag = "";
                if (n == 1)
                    tag = "i";
                else if (n == 2)
                    tag = "b";
                else if (n == 3)
                    tag = "mark";

                int j = 0;
                while (buff[i + j + n] != '*' && buff[i + j + n - 1] != '\\')
                    j++;

                char *internal = malloc(j + 1);
                memcpy(internal, buff + i + n, j);
                internal[j] = '\0';

                size_t append_line_length = snprintf(NULL, 0, "<%s>%s</%s>", tag, internal, tag) + 1;
                char *append = malloc(append_line_length);
                char *tmp_out = realloc(*out, strlen(*out) + append_line_length);
                if (append == NULL || tmp_out == NULL)
                {
                    perror("Couldn't allocate memory for new element");
                    continue;
                }
                *out = tmp_out;

                snprintf(append, append_line_length, "<%s>%s</%s>", tag, internal, tag);
                strcat(*out, append);

                i += n * 2 + j - 1;

                free(append);
                free(internal);

                continue;
            }

            if (buff[i] == '!' && buff[i + 1] == '[')
            {
                int n = 0;
                while (buff[i + 2 + n] != ']')
                    n++;

                if (buff[i + 2 + n + 1] == '(')
                {
                    int k = 0;
                    while (buff[i + 2 + n + 2 + k] != ')')
                        k++;

                    char *internal_text = malloc(n + 1);
                    memcpy(internal_text, buff + i + 2, n);
                    internal_text[n] = '\0';

                    char *src = malloc(k + 1);
                    memcpy(src, buff + i + 2 + n + 2, k);
                    src[k] = '\0';

                    size_t append_line_length = snprintf(NULL, 0, "<a href=\"%s\"><img src=\"%s\" alt=\"%s\"></a>", src, src, internal_text) + 1;
                    char *append = malloc(append_line_length);
                    char *tmp_out = realloc(*out, strlen(*out) + append_line_length);
                    if (append == NULL || tmp_out == NULL)
                    {
                        perror("Couldn't allocate memory for new element");
                        continue;
                    }
                    *out = tmp_out;

                    snprintf(append, append_line_length, "<a href=\"%s\"><img src=\"%s\" alt=\"%s\"></a>", src, src, internal_text);
                    strcat(*out, append);

                    i += 2 + n + 2 + k;

                    free(append);
                    free(src);
                    free(internal_text);

                    continue;
                }
            }

            if (buff[i] == '[')
            {
                int n = 0;
                while (buff[i + 1 + n] != ']')
                    n++;

                if (buff[i + 1 + n + 1] == '(')
                {
                    int k = 0;
                    while (buff[i + 1 + n + 2 + k] != ')')
                        k++;

                    char *internal_text = malloc(n + 1);
                    memcpy(internal_text, buff + i + 1, n);
                    internal_text[n] = '\0';

                    char *href = malloc(k + 1);
                    memcpy(href, buff + i + 1 + n + 2, k);
                    href[k] = '\0';

                    size_t append_line_length = snprintf(NULL, 0, "<a href=\"%s\">%s</a>", href, internal_text) + 1;
                    char *append = malloc(append_line_length);
                    char *tmp_out = realloc(*out, strlen(*out) + append_line_length);
                    if (append == NULL || tmp_out == NULL)
                    {
                        perror("Couldn't allocate memory for new element");
                        continue;
                    }
                    *out = tmp_out;

                    snprintf(append, append_line_length, "<a href=\"%s\">%s</a>", href, internal_text);
                    strcat(*out, append);

                    i += 1 + n + 2 + k;

                    free(append);
                    free(href);
                    free(internal_text);

                    continue;
                }
            }

            size_t len = strlen(*out);
            char *tmp_out = realloc(*out, len + 2);
            if (tmp_out == NULL)
            {
                perror("Couldn't allocate more memory to porcess Markdown");
                return -1;
            }
            *out = tmp_out;
            (*out)[len] = buff[i];
            (*out)[len + 1] = '\0';
        }

        tmp_out = realloc(*out, strlen(*out) + strlen("</p>") + 1);
        if (tmp_out == NULL)
        {
            perror("Couldn't allocate memory for new element");
            continue;
        }
        *out = tmp_out;

        strcat(*out, "</p>");

        size_t len = strlen(*out);
        if ((*out)[len - 1] != '\n')
        {
            char *tmp_out = realloc(*out, len + 2);
            if (tmp_out == NULL)
            {
                perror("Couldn't allocate more memory to porcess Markdown");
                return -1;
            }
            *out = tmp_out;
            (*out)[len] = '\n';
            (*out)[len + 1] = '\0';
        }
    }
    (*out)[strlen(*out) - 1] = '\0';

    free(free_rest);

    return strlen(*out);
}
