#include "ansi.h"
#include "dht.h"
#include "TinyDebug.h"
#include "TinyWireM.h"

#define DS1307_ADDR 0x68       // Endereço I2C do DS1307
#define DHT22_PIN   1          // Define o pino do sensor de temperatura e humidade

ANSI ansi(&Debug);

dht DHT;

uint8_t wireRet = 0;
uint8_t seconds;
uint8_t minutes;
uint8_t hours;
uint8_t dayOfWeek;
uint8_t day;
uint8_t month;
uint16_t year;

float temperature;
float humidity;

unsigned long timerUpdate = 0;

void setup() {
  Debug.begin();
  TinyWireM.begin();

  // Configura a porta do sensor como entrada
  pinMode(DHT22_PIN, INPUT);

  delay(1000);

  ansi.clearScreen();
  ansi.gotoXY(2, 2);
  ansi.bold();
  ansi.foreground(ansi.cyan);
  ansi.print("WOKWI ANSI TERMINAL EXAMPLE");
  ansi.normal();
  delay(3000);
  ansi.clearScreen();
}

void loop()
{
  if (millis() - timerUpdate >= 1000) {
    timerUpdate = millis();
    // Retorna os valores da data e hora
    requestDateTime();

    // Retorna os valores da humidade e temperatura
    DHT.read22(DHT22_PIN);

    // Atualiza a temperatura
    temperature = DHT.temperature;

    // Atualiza a humidade
    humidity = DHT.humidity;

    // Corrige a temperatura negativa
    if (temperature < 0) {
      temperature = -((uint8_t)temperature - 52);
    }

    ansi.normal();

    // Display temperatura
    ansi.gotoXY(5, 10);
    ansi.print("TEMP:       ");
    ansi.gotoXY(5, 16);

    if (temperature < 0)
      ansi.foreground(ansi.white);

    if (temperature > 0)
      ansi.foreground(ansi.green);

    if (temperature > 33)
      ansi.foreground(ansi.yellow);

    if (temperature > 66)
      ansi.foreground(ansi.red);

    ansi.print(temperature);
    ansi.print(" °C      ");
    ansi.foreground(ansi.white);

    // Display humidade
    ansi.gotoXY(5, 30);
    ansi.print(" HUM:       ");
    ansi.gotoXY(5, 36);

    if (humidity < 20)
      ansi.foreground(ansi.red);

    if (humidity > 20)
      ansi.foreground(ansi.yellow);

    if (humidity > 60)
      ansi.foreground(ansi.green);

    if (humidity > 60)
      ansi.foreground(ansi.green);

    ansi.print(humidity);
    ansi.print(" %    ");

    // Display bargraph (dummy)
    ansi.gotoXY(8, 7);
    ansi.print("PROGRESS SAMPLE:");
    ansi.gotoXY(8, 24);

    int x = humidity / 5;

    for (int i = 0; i <= 20; i++) {
      ansi.print(i < x ? "█" : " ");
    }

    ansi.foreground(ansi.white);
    ansi.gotoXY(8, 45);
    ansi.print(humidity);
    ansi.print("%   ");

    // Display date
    ansi.gotoXY(2, 10);
    ansi.print("DATE:         ");
    ansi.gotoXY(2, 16);
    ansi.bold();
    ansi.foreground(ansi.cyan);
    ansi.print(formatDate(day, month, year));

    // Display time
    ansi.gotoXY(2, 30);
    ansi.normal();
    ansi.foreground(ansi.white);
    ansi.print("TIME:         ");
    ansi.gotoXY(2, 36);
    ansi.bold();
    ansi.foreground(ansi.cyan);   
    ansi.print(formatTime(hours, minutes, seconds));
  }
}

void requestDateTime() {
  TinyWireM.beginTransmission(DS1307_ADDR);      // Redefine endereço de dados do DS1307
  TinyWireM.send(0x00);
  wireRet = TinyWireM.endTransmission();

  // Solicita 7 bytes do DS1307
  TinyWireM.requestFrom(DS1307_ADDR, 7);
  seconds = bcdToDec(TinyWireM.receive() & 0x7F);
  minutes = bcdToDec(TinyWireM.receive());
  hours = bcdToDec(TinyWireM.receive());
  dayOfWeek = TinyWireM.receive();
  day = bcdToDec(TinyWireM.receive());
  month = bcdToDec(TinyWireM.receive());
  year = bcdToDec(TinyWireM.receive()) + 2000;
}

// Converte decimais codificados em binários para números decimais normais
uint8_t bcdToDec(uint8_t value) {
  return ((value / 16 * 10) + (value % 16));
}

// Formata os dados da data do RTC (dd/mm/yyyy)
char* formatDate(int8_t d, int8_t m, int16_t y) {
  static char date[11] = {'\0'};
  snprintf(date, sizeof(date), "\%02d/\%02d/\%04d", d, m, y);
  return date;
}

// Formata os dados da hora do RTC (hh:mm:ss)
char* formatTime(int8_t hour, int8_t minute, int8_t second) {
  static char time[9] = {'\0'};
  snprintf(time, sizeof(time), "\%02d:\%02d:\%02d", hour, minute, second);
  return time;
}

// Formata os dados da temperatura (Temp. 00.0C)
char* formatTemperature(float temp) {
  static char temp_char[13] = {'\0'};
  snprintf(temp_char, sizeof(temp_char), "Temp. %02d.%01dC",
           (int)temp, (int)(temp * 100) % 100);
  return temp_char;
}

// Formata os dados da humidade (HR 00.0%)
char* formatHumidity(float hum) {
  static char hum_char[11] = {'\0'};
  snprintf(hum_char, sizeof(hum_char), "HR %02d.%01d%%",
           (int)hum, (int)(hum * 100) % 100);
  return hum_char;
}
GND5VSDASCLSQWRTCDS1307+