// Copyright 2024 jack (@waffle87)
// SPDX-License-Identifier: GPL-2.0-or-later
#include "waffle.h"
uint32_t oled_timer = 0;

void render_wpm(void) {
  oled_write(PSTR("WPM: "), false);
  oled_write_ln(get_u8_str(get_current_wpm(), ' '), false);
}

#ifdef DEBUG_MATRIX_SCAN_RATE
void render_scan_rate(void) {
  oled_write(get_u16_str(get_matrix_scan_rate(), ' '), false);
  oled_write_ln(PSTR("/s"), false);
}
#endif

#ifdef RAW_ENABLE
void host_info(uint8_t data) {
  char buffer[3];
  oled_write_ln((char *)itoa(data, buffer, 10), false);
}

void render_time(void) {
  if (user_state.hour < 10)
    oled_write(PSTR("0"), false);
  host_info(user_state.hour);
  oled_write(PSTR(":"), false);
  if (user_state.min < 10)
    oled_write(PSTR("0"), false);
  host_info(user_state.min);
}
#endif

void qmk_logo(void) {
  static const char PROGMEM qmk_logo[16] = {0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0xaa,
                                            0xab, 0xac, 0xad, 0xae, 0xca, 0xcb,
                                            0xcc, 0xcd, 0xce, 0};
  oled_write(qmk_logo, false);
};

void render_keyboard(void) {
  static const char PROGMEM keyboard[16] = {0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xda,
                                            0xdb, 0xdc, 0xdd, 0xde, 0};
  oled_write(keyboard, false);
};

void layer_status(void) {
  bool blink = (timer_read() % 1000) < 500;
  switch (get_highest_layer(layer_state)) {
  case _RAISE:
    oled_write_ln(PSTR("> hi"), false);
    break;
  case _LOWER:
    oled_write_ln(PSTR("> lo"), false);
    break;
  case _ADJUST:
    oled_write_ln(PSTR("> ad"), false);
    break;
  default:
    oled_write_ln(blink ? PSTR("> _") : PSTR(">   "), false);
  }
};

void mod_status(uint8_t mods) {
  static const char PROGMEM status[4][3] = {
      {0xd3, 0xd4, 0}, {0x93, 0x94, 0}, {0xb3, 0xb4, 0}, {0x95, 0x96, 0}};
  bool blink = (timer_read() % 1000) < 500;
  if (mods & MOD_MASK_CTRL) {
    oled_set_cursor(2, 11);
    oled_write(status[0], false);
  } else if (mods & MOD_MASK_SHIFT) {
    oled_set_cursor(2, 11);
    oled_write(status[1], false);
  } else if (mods & MOD_MASK_ALT) {
    oled_set_cursor(2, 11);
    oled_write(status[2], false);
  } else if (mods & MOD_MASK_GUI) {
    oled_set_cursor(2, 11);
    oled_write(status[3], false);
  } else
    oled_write_ln(blink ? PSTR("$ _") : PSTR("$   "), false);
}

void keylock_status(led_t led_usb_state) {
  bool blink = (timer_read() % 1000) < 500;
  if (led_usb_state.caps_lock)
    oled_write_ln(PSTR("% cap"), false);
  else if (led_usb_state.num_lock)
    oled_write_ln(PSTR("% num"), false);
  else if (led_usb_state.scroll_lock)
    oled_write_ln(PSTR("% scr"), false);
  else
    oled_write_ln(blink ? PSTR("% _") : PSTR("%    "), false);
}

char keylog_str[5] = {};
static uint16_t keylog_timer = 0;
const char code_to_name[60] = {
    ' ', ' ',  ' ', ' ', 'a',  'b', 'c', 'd', 'e', 'f', 'g', 'h',
    'i', 'j',  'k', 'l', 'm',  'n', 'o', 'p', 'q', 'r', 's', 't',
    'u', 'v',  'w', 'x', 'y',  'z', '1', '2', '3', '4', '5', '6',
    '7', '8',  '9', '0', 'R',  'E', 'B', 'T', '_', '-', '=', '[',
    ']', '\\', '#', ';', '\'', '`', ',', '.', '/', ' ', ' ', ' '};

void add_keylog(uint16_t keycode) {
  for (uint8_t i = ARRAY_SIZE(keylog_str) - 1; i > 0; i--)
    keylog_str[i] = keylog_str[i - 1];
  if (keycode < ARRAY_SIZE(code_to_name))
    keylog_str[0] = code_to_name[keycode & 0xFF];
  keylog_timer = timer_read();
}

void render_keylog(void) { oled_write(keylog_str, false); }

void render_keylogger(void) { oled_write(keylog_str, false); }

void keylogger_status(void) {
  bool blink = (timer_read() % 1000) < 500;
  oled_write_ln(blink ? PSTR("~ _") : PSTR("~  "), false);
}

void anim_frame(uint16_t size, char const action[][size]) {
  static uint8_t current_frame = 0;
  current_frame = (current_frame + 1) & 1;
  oled_write_raw(action[current_frame], size);
}

#ifdef FELIX_DOG
void felix(void) {
  static uint16_t felix_anim_timer = 0;
  bool shifted = get_mods() & MOD_MASK_SHIFT ||
                 host_keyboard_led_state().caps_lock || is_caps_word_on();
  void animate(void) {
    if (shifted)
      anim_frame(96, felix_bark);
    else if (get_mods() & MOD_MASK_CAG)
      anim_frame(96, felix_sneak);
    else if (get_current_wpm() > 40)
      anim_frame(96, felix_run);
    else if (get_current_wpm() > 30 && get_current_wpm() <= 40)
      anim_frame(96, felix_walk);
    else
      anim_frame(96, felix_sit);
  }
  if (timer_elapsed(felix_anim_timer) > 200) {
    felix_anim_timer = timer_read();
    animate();
  }
}
#endif

#ifdef BONGO_CAT
void bongo(void) {
  static uint16_t bongo_anim_timer = 0;
  void animate(void) {
    if (get_current_wpm() <= 30) {
      anim_frame(512, bongo_idle);
    }
    if (get_current_wpm() > 30 && get_current_wpm() <= 40) {
      anim_frame(512, bongo_prep);
    }
    if (get_current_wpm() > 40) {
      anim_frame(512, bongo_tap);
    }
  }
  if (timer_elapsed(bongo_anim_timer) > 200) {
    bongo_anim_timer = timer_read();
    animate();
  }
}
#endif

#ifdef WPM_GRAPH
void wpm_graph(void) {
  static uint8_t height = OLED_DISPLAY_HEIGHT - 1, vert_count = 0,
                 max_wpm = 160;
  static uint16_t graph_timer = 0;
  if (timer_elapsed(graph_timer) > 100) {
    height = 63 - ((get_current_wpm() / (float)max_wpm) * 63);
    for (uint8_t i = 0; i <= 1; i++)
      oled_write_pixel(3, height + i, true);
    if (vert_count == 3) {
      vert_count = 0;
      while (height <= 63) {
        oled_write_pixel(3, height, true);
        height++;
      }
    } else {
      for (uint8_t i = 63; i > height; i--)
        if (!(i % 3))
          oled_write_pixel(3, i, true);
      vert_count++;
    }
    for (uint16_t y = 0; y < 8; y++) {
      for (uint16_t x = 124; x > 0; x--) {
        uint16_t i = y * OLED_DISPLAY_WIDTH + x;
        oled_buffer[i] = oled_buffer[i - 1];
        oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE));
      }
    }
    graph_timer = timer_read();
  }
}
#endif

#ifdef LAYER_ANIM
void layer_anim(void) {
  static uint16_t layer_anim_timer = 0;
  void animate(void) {
    switch (get_highest_layer(layer_state)) {
    case _RAISE:
      anim_frame(650, tap_sym);
      break;
    case _LOWER:
      anim_frame(520, tap_num);
      break;
    case _ADJUST:
      anim_frame(520, tap_sys);
      break;
    default:
      bongo();
    }
  }
  if (timer_elapsed(layer_anim_timer) > 200) {
    layer_anim_timer = timer_read();
    animate();
  }
}
#endif

bool oled_task_user(void) {
  if (is_keyboard_master()) {
    if (timer_elapsed32(oled_timer) > 180000) {
      oled_off();
      return false;
    } else
      oled_on();
  }
  oled_task_keymap();
  return false;
}

void oled_timer_reset(void) { oled_timer = timer_read32(); }