#pragma once

#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>

namespace tbeam {

struct DisplayConfig {
  int sda = -1;
  int scl = -1;
  uint8_t address = 0x3C;
  bool beginWire = true;
  bool powerSave = false;
};

enum class DisplayFont : uint8_t {
  SMALL = 0,
  NORMAL,
  LARGE
};

class TBeamDisplay {
 public:
  static constexpr uint8_t kMaxLines = 6;
  static constexpr uint8_t kLineBytes = 32;

  explicit TBeamDisplay(TwoWire& wire = Wire);

  bool begin(const DisplayConfig& config = DisplayConfig{});
  void update();

  bool ready() const { return ready_; }
  bool powerSave() const { return powerSave_; }
  const char* lastError() const { return lastError_; }

  void clear();
  void clearBuffer();
  void setPowerSave(bool enabled);
  void setFont(DisplayFont font);
  void showLines(const char* l1,
                 const char* l2 = nullptr,
                 const char* l3 = nullptr,
                 const char* l4 = nullptr,
                 const char* l5 = nullptr,
                 const char* l6 = nullptr);
  void setLine(uint8_t index, const char* text);
  void renderLines(uint8_t lineCount = kMaxLines);
  void appendLine(const char* text);
  void showBoot(const char* title, const char* subtitle = nullptr, const char* detail = nullptr);
  void showStatus(const char* title, const char* left, const char* right = nullptr, const char* footer = nullptr);

  U8G2& raw() { return oled_; }

 private:
  void setError(const char* message);
  void clearError();
  const uint8_t* fontFor(DisplayFont font) const;

  TwoWire& wire_;
  DisplayConfig config_{};
  U8G2_SH1106_128X64_NONAME_F_HW_I2C oled_{U8G2_R0, U8X8_PIN_NONE};
  bool ready_ = false;
  bool powerSave_ = false;
  DisplayFont font_ = DisplayFont::NORMAL;
  char lines_[kMaxLines][kLineBytes] = {};
  char lastError_[96] = {};
};

}  // namespace tbeam
