#pragma once
#include <cstdint>
#include <optional>
#include <string>
#include <map>
#include <variant>
#include <vector>

namespace lsp::protocol
{

    using integer = std::int32_t;
    using uinteger = std::uint32_t;
    using decimal = double;
    using boolean = bool;
    using string = std::string;

    // LSPAny 这样设计是为了glaz序列化
    struct LSPAny;
    using LSPObject = std::map<string, LSPAny>;
    using LSPArray = std::vector<LSPAny>;

    struct LSPAny
    {
        using LSPAnyVariant = std::variant<
            LSPObject,
            LSPArray,
            string,
            decimal, // 放在前面，优先匹配数字
            boolean,
            std::nullptr_t>;

        LSPAnyVariant value;

        // 默认构造函数
        LSPAny();
        // 拷贝和移动构造函数
        LSPAny(const LSPAny& other);
        LSPAny(LSPAny&& other) noexcept;
        // 针对每种支持的类型的构造函数
        LSPAny(const std::map<string, LSPAny>& val);
        LSPAny(std::map<string, LSPAny>&& val);
        LSPAny(const std::vector<LSPAny>& val);
        LSPAny(std::vector<LSPAny>&& val);
        LSPAny(const string& val);
        LSPAny(string&& val);
        LSPAny(const char* val);

        // 所有数字类型都转换为 decimal
        LSPAny(int val);
        LSPAny(long val);
        LSPAny(long long val);
        LSPAny(unsigned int val);
        LSPAny(unsigned long val);
        LSPAny(unsigned long long val);
        LSPAny(float val);
        LSPAny(double val);
        LSPAny(long double val);
        LSPAny(boolean val);
        LSPAny(std::nullptr_t);

        // 赋值操作符
        LSPAny& operator=(const LSPAny& other);
        LSPAny& operator=(LSPAny&& other) noexcept;
        LSPAny& operator=(const std::map<string, LSPAny>& val);
        LSPAny& operator=(std::map<string, LSPAny>&& val);
        LSPAny& operator=(const std::vector<LSPAny>& val);
        LSPAny& operator=(std::vector<LSPAny>&& val);
        LSPAny& operator=(const string& val);
        LSPAny& operator=(string&& val);
        LSPAny& operator=(const char* val);
        LSPAny& operator=(int val);
        LSPAny& operator=(long val);
        LSPAny& operator=(long long val);
        LSPAny& operator=(unsigned int val);
        LSPAny& operator=(unsigned long val);
        LSPAny& operator=(unsigned long long val);
        LSPAny& operator=(float val);
        LSPAny& operator=(double val);
        LSPAny& operator=(long double val);
        LSPAny& operator=(boolean val);
        LSPAny& operator=(std::nullptr_t);

        // 类型检查辅助函数
        template<typename T>
        bool is() const;

        template<typename T>
        T& get();

        template<typename T>
        const T& get() const;

        // 访问操作符
        template<typename Visitor>
        auto visit(Visitor&& visitor) const;

        template<typename Visitor>
        auto visit(Visitor&& visitor);
    };

    using ProgressToken = std::variant<integer, string>;

    template<typename T>
    struct ProgressParams
    {
        ProgressToken token;
        T value;
    };

    using DocumentUri = string;
    using URI = string;

    struct Position
    {
        uinteger line;
        uinteger character;
    };

    using PositionEncodingKind = std::string_view;
    namespace PositionEncodingKindLiterals
    {
        inline constexpr PositionEncodingKind UTF8 = "utf-8";
        inline constexpr PositionEncodingKind UTF16 = "utf-16";
        inline constexpr PositionEncodingKind UTF32 = "utf-32";
    }

    struct Range
    {
        Position start;
        Position end;
    };

    struct DocumentFilter
    {
        string language;
        string scheme;
        std::optional<string> pattern;
    };

    using DocumentSelector = std::vector<DocumentFilter>;

    struct TextEdit
    {
        Range range;
        string newText;
    };

    struct ChangeAnnotation
    {
        string label;
        boolean needsConfirmation;
        string description;
    };

    using ChangeAnnotationIdentifier = string;

    struct AnnotatedTextEdit : TextEdit
    {
        ChangeAnnotationIdentifier annotationId;
    };

    struct Location
    {
        DocumentUri uri;
        Range range;
    };

    struct LocationLink
    {
        Range originSelectionRange;
        DocumentUri targetUri;
        Range targetRange;
        Range targetSelectionRange;
    };

    struct Command
    {
        string title;
        string command;
        std::optional<LSPAny> arguments;
    };

    using MarkupKind = std::string_view;
    namespace MarkupKindLiterals
    {
        inline constexpr MarkupKind PlainText = "plaintext";
        inline constexpr MarkupKind Markdown = "markdown";
    };

    struct MarkupContent
    {
        MarkupKind kind;
        string value;
    };

    struct RegularExpressionsClientCapabilities
    {
        string engine;
        std::optional<string> version;
    };

    struct MarkdownClientCapabilities
    {
        string parser;
        std::optional<string> version;
        std::optional<std::vector<string>> allowedTags;
    };

    // LSP模板方法
    template<typename T>
    bool LSPAny::is() const
    {
        return std::holds_alternative<T>(value);
    }

    template<typename T>
    T& LSPAny::get()
    {
        return std::get<T>(value);
    }

    template<typename T>
    const T& LSPAny::get() const
    {
        return std::get<T>(value);
    }

    // 访问操作符
    template<typename Visitor>
    auto LSPAny::visit(Visitor&& visitor) const
    {
        return std::visit(std::forward<Visitor>(visitor), value);
    }

    template<typename Visitor>
    auto LSPAny::visit(Visitor&& visitor)
    {
        return std::visit(std::forward<Visitor>(visitor), value);
    }

}

#include "./lsp_any.inl"
