#include <str.hpp>

#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>


auto constexpr first  = 1;
auto constexpr second = 2;
auto constexpr third  = 3;

std::string static str_case_(int value)
{
    switch(value)
    {
        STR_CASE(first)
        STR_CASE(second)
        STR_CASE(third)
        default:
            return "unknown";
    }
}

std::string static str_cond_(int value)
{
    return
        STR_COND(value, first)
        STR_COND(value, second)
        STR_COND(value, third)
        "unknown";
}

std::string static str_init_(int value)
{
    auto str = std::unordered_map<int, std::string>{
        STR_INIT(first)
        STR_INIT(second)
        STR_INIT(third)
    }[value];
    if (str.empty())
        return "unknown";
    return str;
}


void static func_inner_()
{
    try
    {
        STR_THROW(
            "Expected " << "this" << ", " <<
            "got "      << "that" << "."
        );
    }
    catch (...)
    {
        STR_NESTED_THROW("Failed to do " << "inner" << ":");
    }
}

void static func_outer_()
{
    try
    {
        func_inner_();
    }
    catch (...)
    {
        STR_NESTED_THROW("Failed to do " << "outer" << ":");
    }
}


int main()
{
    auto const value  = 0x03;
    auto const values = std::vector<std::string>{"first", "", "third"};
    std::cout << STR(     std::hex << std::showbase << value)   << std::endl;
    std::cout << STR_FUNC(std::hex << std::showbase << value)() << std::endl;
    std::cout << STR_JOIN(", ", it, "\"" << it << "\"", values) << std::endl;
    std::cout << STR_JOIN_INIT(", ", it, it, int, {1, 2, 3}) << std::endl;
    std::cout << STR_JOIN_INITSTR(", ", it, it, {
        std::string{"first"},
        "",
        "third",
    }) << std::endl;

    std::cout << std::endl;

    std::cout << str_case_(1) << std::endl; // Uses `STR_CASE`.
    std::cout << str_cond_(0) << std::endl; // Uses `STR_COND`.
    std::cout << str_init_(3) << std::endl; // Uses `STR_INIT`.

    std::cout << std::endl;

    std::cout << STR_HERE("Hello from " << "here") << std::endl;

    std::cout << std::endl;

    try
    {
        STR_THROW_ERRNO();
    }
    catch (std::exception const & exception)
    {
        std::cout << exception.what() << std::endl;
    }

    try
    {
        func_outer_();
    }
    catch (std::exception const & exception)
    {
        // TODO(rcrnstn): There may be a bug in `clang-tidy` 13, check if
        // `STR_NESTED_WHAT` passes with a newer version.
        // NOLINTNEXTLINE
        std::cout << STR_NESTED_WHAT("\n", exception) << std::endl;
    }
}