#include <source_location>

#include "log.h"
#include "show.h"
#include "util.h"

int verbose_level = 0;

using log_arg = std::variant<bool,int,float,std::string,const char*,Locator>;

std::ostream& operator<<(std::ostream& os, const log_arg& arg)
{
    bool quoted_string = verbose_level > 2;
    if (std::holds_alternative<bool>(arg)) {
        os << (std::get<bool>(arg) ? "true" : "false");
    } else if (std::holds_alternative<int>(arg)) {
        os << std::get<int>(arg);
    } else if (std::holds_alternative<float>(arg)) {
        os << std::get<float>(arg);
    }
    else if (std::holds_alternative<std::string>(arg)) {
        std::string s = std::get<std::string>(arg);
        if (quoted_string)
            os << "\"";
        if (!quoted_string && s.empty()) {
            os << "<none>";
        } else {
            os << s;
        }
        if (quoted_string)
            os << "\"";
    } else if (std::holds_alternative<const char*>(arg)) {
        os << std::get<const char*>(arg);
//    } else if (std::holds_alternative<strings_t>(arg)) {
//        os << std::get<strings_t>(arg);
    } else if (std::holds_alternative<Locator>(arg)) {
        os << std::get<Locator>(arg);
//    } else if (std::holds_alternative<Source>(arg)) {
//        os << std::get<Source>(arg);
//    } else if (std::holds_alternative<katom_t>(arg)) {
//        os << std::get<katom_t>(arg);
//    } else if (std::holds_alternative<Katom>(arg)) {
//        os << std::get<Katom>(arg);
    }
    /*
    } else if (std::holds_alternative<katom_list>(arg)) {
        os << std::get<katom_list>(arg);
    } else if (std::holds_alternative<katom_iter>(arg)) {
        os << std::get<katom_iter>(arg);
    }
    */
    return os;
}

void log_indent(const std::string& filename, const Color& color)
{
    std::cerr
        << color
        << std::setfill(' ')
        << std::setw(22-static_cast<int>(std::size(filename)))
        << std::right;
}

void log_filepos(const std::string& filename, int line, const Color& color)
{
//    if (show_verbose_location) {
        log_indent(filename, color);
        std::cerr
            << "[" << filename << ":"
            << std::setw(3) << std::setfill('0')
            << line << "] " << reset;
//    }
}

std::string prettify_name(const std::string& s)
{
    std::string result = s;
    result = string_replace(result, "std::__cxx11::basic_string<char>", "std::string");
    result = string_replace(result, " >", ">");

    std::smatch match;
    std::regex re(R"(.*?(\w+)\(.*)");
    if (verbose_level < 4 && std::regex_search(result, match, re)) {
        std::stringstream ss;
        ss << match[1] << "()";
        result = ss.str();
    }
    return result;
}
                            
void display_location(int log_level, std::source_location location)
{
    if (verbose_level >= log_level) {
        Color color = blue; // cyan;
        if (log_level == 1) {
            color = magenta;
        }
        if (verbose_level > 1) {
            log_filepos(location.file_name() ? location.file_name() : "",
                        location.line(), color);
        }
        if (verbose_level > 3) {
            std::cerr << location.function_name();
        } else if (verbose_level > 1) {
            std::cerr << prettify_name(location.function_name());
        }
    }
}

void warning(const std::string& message, const Locator& loc)
{
    std::cerr << "  " << red << command_name << " (warning): " << message << "\n";
    if (loc.m_filename != "") {
        std::cerr << "  " << loc.desc();
    }
    std::cerr << "\n" << reset;
}
