#pragma once
#include <luna/Result.h>
#include <luna/StringView.h>
#include <stdarg.h>

class String
{
    typedef char* Iterator;
    typedef const char* ConstIterator;

  public:
    /* Constructs a String, which will take ownership of the given c-string. To create a String that makes its own
     * internal copy of the passed string, use String::from_cstring(). */
    String(char* c_str);

    /* Constructs a String with precalculated length, which will take ownership of the given c-string. To create a
     * String that makes its own internal copy of the passed string, use String::from_cstring(). */
    String(char* c_str, usize length);

    /* Constructs an empty String. */
    String();

    String(String&&);

    /* Implicit copying is disabled for Strings, as copy constructors cannot use value-based error handling. To copy a
     * string, please use the clone() method. */
    String(const String&) = delete;

    String& operator=(String&&);

    /* Implicit copying is disabled for Strings, as copy constructors cannot use value-based error handling. To copy a
     * string, please use the clone() method. */
    String& operator=(const String&) = delete;

    ~String();

    /* Creates a copy of this String and returns it. */
    Result<String> clone() const;

    /* Creates a copy of a specific segment of this String and returns it. */
    Result<String> substring(usize begin, usize size) const;

    /* Splits a String with a delimiter. */
    Result<Vector<String>> split(StringView delim) const
    {
        return view().split(delim);
    }

    /* Splits a String into two parts with a delimiter. */
    Result<Vector<String>> split_once(char delim) const
    {
        return view().split_once(delim);
    }

    /* Creates a single String consisting of a list of strings separated by a delimiter. */
    static Result<String> join(const Vector<String>& vec, StringView delim);

    /* Creates a single String consisting of a list of strings separated by a delimiter. */
    static Result<String> join(const Vector<StringView>& vec, StringView delim);

    /* Removes all trailing characters contained in delim. */
    void trim(StringView delim);

    static Result<String> format(const String& fmt, ...);
    static Result<String> format(StringView fmt, ...);
    static Result<String> vformat(StringView fmt, va_list ap);

    static Result<String> from_cstring(const char* str);
    static Result<String> from_string_view(StringView str);

    static int compare(const String* a, const String* b);

    const char* chars() const
    {
        return m_inline ? m_inline_storage : m_string;
    }

    usize length() const
    {
        return m_length;
    }

    bool is_empty() const
    {
        return m_length == 0;
    }

    StringView view() const
    {
        return { chars(), m_length };
    }

    const char& operator[](usize) const;

    Iterator begin()
    {
        return m_inline ? m_inline_storage : m_string;
    }

    ConstIterator begin() const
    {
        return chars();
    }

    Iterator end()
    {
        return begin() + m_length;
    }

    ConstIterator end() const
    {
        return begin() + m_length;
    }

  private:
    union {
        char* m_string { nullptr };
        char m_inline_storage[sizeof(char*)];
    };

    bool m_inline { true };

    usize m_length { 0 };

    void empty();
};