#pragma once

#include <string>
#include <variant>
#include <functional>
#include <regex>

#include "locator.h"

using argtype_t = std::variant<bool,double,std::string,std::vector<std::string>>;

using modify_string_f = std::function<std::string(std::vector<std::string>)>;

class Argtype
{
public:
    Argtype()
        : m_name("default")
        , m_desc("default argument type")
        , m_symbolic_pattern(R"((?:.|\n)*)")
        , m_pattern(R"((?:.|\n)*)")
        , m_python_cast("str")
        , m_python_format()
        , m_regex(std::regex(R"((?:.|\n)*)"))
        , m_loc()
        {};

    Argtype(const std::string& name, const std::string& desc, const std::string& symbolic_pattern,
            const std::string& pattern,
            const std::string& default_value, const std::string& alone_value,
            const std::string& python_cast, const modify_string_f& python_format,
            const Locator& loc);

    std::string python_value(const std::string& var_name, std::vector<std::string> value, size_t name_size);

    // True for the match-everything pattern shared by the string family
    // (string, rest, literal, and the default type).  Validating against
    // it is pointless, and running std::regex over a large value (e.g.
    // @document's :text holding a whole document) overflows the regex
    // executor's recursion stack.
    bool matches_all() const { return m_pattern == R"((?:.|\n)*)"; };

    std::string m_name {};
    std::string m_desc {};
    std::string m_symbolic_pattern {};
    std::string m_pattern {};
    // Default value for parameters of this type; a default given in a
    // klammer's parameter declaration overrides it (see
    // parse_optional_parameter).  Useful for single-purpose types
    // (cell_hpos, column_width); general types (bool, float) have no
    // sensible universal default and leave it empty.
    std::string m_default {};
    // Value for an optional argument whose name is written alone, with no
    // value after it (:number rather than :number 10).  Declared by the
    // argument type, never by a klammer's parameter declaration: the
    // default is what a klammer means by silence and is properly
    // per-klammer, but a bare option name must read the same way in every
    // klammer or the writer cannot know what it means without consulting
    // each signature.  bool declares "true", which is where the
    // presence-means-true convention comes from; a type whose pattern
    // matches everything cannot declare it (the value would swallow the
    // following text instead).  Empty means the type has no alone value,
    // and a bare option name yields the empty string as before.
    std::string m_alone {};
    // Type parameter for parameterized types like rest(2): the value N
    // is bound around the python cast as (lambda N: <cast>)(2)(...).
    // Empty means unparameterized; a type with a default parameter
    // (rest -> "1") is specialized by writing type(N) in a declaration.
    std::string m_parameter {};
    std::string m_python_cast {};
    modify_string_f m_python_format {};
    std::regex m_regex {};
    int m_count {1};
    int m_mincount {1};
    int m_maxcount {1};
    Locator m_loc;

};

std::string pyformat_string(const std::vector<std::string>& value);
std::string pyformat_bool(const std::vector<std::string>& value);
std::string pyformat_number(const std::vector<std::string>& value);
std::string pyformat_list(const std::vector<std::string>& value);
std::string pyformat_dlist(const std::vector<std::string>& value);
