#pragma once
#include <luna/Result.h>
#include <luna/Types.h>
#include <stddef.h>

class Utf8StringDecoder
{
  public:
    Utf8StringDecoder(const char* str);

    usize byte_length() const
    {
        return m_byte_length;
    }

    Result<usize> code_points() const;

    // The caller must ensure that 'buf' is at least code_points() + a NULL wide.
    Result<usize> decode(wchar_t* buf) const;

    Result<usize> decode(wchar_t* buf, usize max) const;

  private:
    const char* m_str;
    usize m_byte_length;
};

class Utf8StringEncoder
{
  public:
    Utf8StringEncoder(const wchar_t* str);

    usize code_points() const
    {
        return m_code_points;
    }

    Result<usize> byte_length() const;

    // The caller must ensure that 'buf' is at least byte_length() + a NULL wide.
    Result<usize> encode(char* buf) const;

    Result<usize> encode(char* buf, usize max) const;

  private:
    const wchar_t* m_str;
    usize m_code_points;
};

class Utf8StateDecoder
{
  public:
    Utf8StateDecoder();

    Result<bool> feed(char c);
    Result<wchar_t> extract();
    void reset();

  private:
    char m_state[4];
    usize m_state_len = 0;
    usize m_state_index = 0;
    wchar_t m_decoded_character;
    bool m_has_character_ready { false };
};

class Utf8Encoder
{
  public:
    // Does not null-terminate. Returns the number of bytes written.
    Result<usize> encode(wchar_t c, char buf[4]);
};