#include <regex>

#include "util.h"
#include "file.h"
#include "html_util.h"
#include "heading.h"
#include "log.h"
#include "show.h"

std::ostream& operator<<(std::ostream& os, const Heading h)
{
    os << h.m_level << " "
       << h.m_filename << " "
       << h.m_section << " "
       << h.m_id << " "
       << h.m_number << " "
       << h.m_title;
    return os;
}

std::string levels_to_section(std::vector<unsigned int> levels)
{
    (void)K::log(3);
    std::string result {};
    auto count = levels.size();
    for (unsigned int i = 0; i < count; i++) {
        if (levels[i] == 0)
            break;
        result += std::to_string(levels[i]);
        if (i < count - 1)
            result += ".";
    }
    if (count > 1)
        result = result.substr(0, result.size()-1);
    return result;
}

int part_number = 1;
int unnumbered_id = 0;

std::string make_html_table_of_contents(std::vector<Heading> headings)
{
    elements_t toc { html::elt("h1", "Contents") };
    for (auto [level, filename, section, id, number, title] : headings) {
        toc.push_back(
            html::elt("div",
                      html::elt("a", {
                              html::elt("span", section).attr("class", "level_number"), 
                              title })
                      .attr("href", "^#" + id)
                      .attr("class", "level"))
            .attr("class", "level" + std::to_string(level)));
    }
    //auto toc_elt = html::elt("div", toc).attr("id", "toc");
    std::string result { "<div id=\"pagetoc\">\n" + to_string(toc) + "\n</div>\n" };
    return result;
}

std::string toc_link_attrs(
    const std::string& section, const std::string& title, const std::string& filename, const std::string& target, int level)
{
    std::string basename = file_basename(filename);
    std::stringstream ss {};
    ss << "class=\"navlink\" data-page=\"" << basename
       << "\" data-target=\"" << target << "\">\n<span class=\"section-title\" level=\"" << level << "\">\n";
    if (section.size() > 0) {
        ss << "<span class=\"section-number\">" << section << "</span>\n";
    }
    ss << "<span class=\"section-title-text\">" << title << "</span>\n"
       << "</span>\n";
    return ss.str();
}


std::pair<int, std::string>
make_navigation_table_of_contents(std::vector<Heading> headings)
{
    std::stringstream toc {};
    long unsigned int i = 1;
    //int max_level = 0;
    //int last_level = 0;
    int max_level = 1;
    int last_level = 1;

    toc << "<ul id=\"toc_items\">\n";
    int min_level = 7;
    for (auto h : headings) {
        min_level = std::min(h.m_level, min_level);
    }

    bool unnumbered_start = headings.size() > 0 ? headings[0].m_section.empty() : false;
    if (unnumbered_start) { // Unnumbered first section (preface, for example)
        toc << "<ul>\n";
    }
    for (auto [item_level, filename, section, id, number, title] : headings) {    
        // msg() << "  level: " << item_level << "; filename: " << filename << "; section: " << section
        //      << "; id: " << id << "; number: " << number << "; title: " << title << "\n";

        bool promote_unnumbered = unnumbered_start && min_level == 0 and section.empty();
        if (promote_unnumbered) {
            item_level--;
        }
        std::string basename = file_basename(filename);
        max_level = std::max(max_level, item_level);
        //int next_level = i < headings.size() ? headings[i].m_level : 0;
        
        int next_level = i < headings.size() ? headings[i].m_level : 1;

        if (promote_unnumbered) {
            next_level = std::max(0, next_level - 1);
        }

        // std::cout << "|" << item_level << "|" << section << "|" << id << "|"
        //        << title << "|  " << "next: " << next_level << "\n";

        std::string link = toc_link_attrs(section, title, basename, id, item_level);

        if (next_level == item_level) {
            toc << "<li " << link << "</li>\n";
            /*
              } else if (next_level > item_level) {
              toc << "<li><span class=\"caret\" data-level=\"" << item_level << "\">"
              << "<span " << link<< "</span></span>\n"
              << "<ul class=\"nested\">\n";
            */
        } else if (next_level > item_level) {
            toc << "<li><span class=\"caret\" data-level=\"" << item_level << "\"></span>\n"
                << "<span " << link<< "</span>\n"
                << "<ul class=\"nested";
            /*
              if (section.size() == 0) {
              toc << " unnumbered";
              }
            */
            toc << "\">\n";
        } else {
            //toc << "<li " << link << "</li>\n</ul>\n</li>\n";
            toc << "<li " << link << "</li>\n";
            /*
            if (unnumbered_start) {
                next_level += 1;
            }
            */
            int offset = unnumbered_start ? 1 : 0;
            //int offset = unnumbered_start ? 3 : 2;
            offset = 0;

            for (int lev = item_level; lev > next_level + offset; lev--) {
                toc << "</ul>\n</li>\n";
            }
            unnumbered_start = false;
        }
        i++;
        last_level = item_level;
    }
    toc << "</ul>\n";
    for (int j = 0; j < last_level - 2; j++) {
        toc << "</li>\n</ul>\n";
    }
    return {max_level, toc.str()};
}

void show_table_of_contents(
    const std::string& kt_root_filename, const std::string& title, std::vector<Heading> headings)
{
    long unsigned int width = kt_root_filename.size();
    for (Heading h : headings) {
        width = std::max(width, h.m_filename.size());
    }
    width += 2;
    int tab = 2;
    std::string current_filename = "";
    std::string bar = "  |  ";
    std::cout << "\n" << std::string(width - kt_root_filename.size(), ' ')
              << kt_root_filename << bar << title << "\n";
    for (auto [level, filename, section, id, number, htitle] : headings) {
        std::string f = "";
        if (filename != current_filename) {
            f = std::string(width - filename.size(), ' ') + filename + bar;
            current_filename = filename;
        } else {
            f = std::string(width, ' ') + bar;
        }
        std::cout << f << std::string((level-1) * tab, ' ') << section << "  " << htitle << "\n";
    }
    std::cout << "\n";
}

std::string cache_table_of_contents(
    const std::string& kt_root_filename, const std::string& title, std::vector<Heading> headings)
{
    long unsigned int width = kt_root_filename.size();
    for (Heading h : headings) {
        width = std::max(width, h.m_filename.size());
    }
    width += 2;
    int tab = 2;
    std::string current_filename = "";
    std::string bar = "  |  ";
    std::stringstream ss {};
    ss << "\n" << std::string(width - kt_root_filename.size(), ' ')
       << kt_root_filename << bar << title << "\n";
    for (auto [level, filename, section, id, number, htitle] : headings) {
        std::string f = "";
        if (filename != current_filename) {
            f = std::string(width - filename.size(), ' ') + filename + bar;
            current_filename = filename;
        } else {
            f = std::string(width, ' ') + bar;
        }
        ss << f << std::string((level) * tab, ' ');
        if (section.size() > 0) {
            ss << section << "  ";
        }
        ss << htitle << "\n";
    }
    ss << "\n";
    std::string cache_filename =
        cache_directory(kt_root_filename, "_html_pages") + "/toc.txt";
    string_to_file(cache_filename, ss.str());
    return cache_filename;
}
