#include "lvgl.h"
#include "pins_config.h"
#include "AXS15231B.h"
#include "ui-util.h"
#include "time.h"
#include <Arduino.h>
#include <SPI.h>

#define set_anim_src(x) ((const void *)trans_ainm_buf[(x)])
#define buf_limit(idx)  ((idx) % 10)
#define timer_h(v, n, obj)                                                       \
    do {                                                                         \
        if (v != n / 10) {                                                       \
            v = buf_limit(n / 10);                                               \
            if (v != 0)                                                          \
                lv_gif_set_src(obj, (const void *)trans_ainm_buf[v - 1]);        \
            else                                                                 \
                lv_gif_set_src(obj, (const void *)trans_ainm_buf[buf_limit(9)]); \
        }                                                                        \
    } while (0);

#define timer_l(v, n, obj)                                                       \
    do {                                                                         \
        if (v != n % 10) {                                                       \
            v = buf_limit(n % 10);                                               \
            if (v != 0)                                                          \
                lv_gif_set_src(obj, (const void *)trans_ainm_buf[v - 1]);        \
            else                                                                 \
                lv_gif_set_src(obj, (const void *)trans_ainm_buf[buf_limit(9)]); \
        }                                                                        \
    } while (0);

static lv_obj_t *dis;
static lv_obj_t *img1;
static lv_obj_t *img2;
static lv_obj_t *img3;
static lv_obj_t *img4;
static lv_obj_t *img5;
static lv_obj_t *img6;
static lv_obj_t *img7;

lv_obj_t *state_symbol;

// Transition animation
static const void *trans_ainm_buf[] = {
    &gif_01, &gif_12, &gif_23, &gif_34, &gif_45,
    &gif_56, &gif_67, &gif_78, &gif_89, &gif_90
};

static void update_text_subscriber_cb_demo1(void *s, lv_msg_t *msg);
static void update_display_state(void *s, lv_msg_t *msg);
void set_flip_time_anim(int hour, int minute, int second);

void ui_begin() {
    dis = lv_tileview_create(lv_scr_act());
    lv_obj_align(dis, LV_ALIGN_TOP_RIGHT, 0, 0);
    lv_obj_set_size(dis, LV_PCT(100), LV_PCT(100));
    lv_obj_set_style_bg_color(dis, lv_color_black(), LV_PART_MAIN | LV_STATE_DEFAULT);

    lv_obj_t *tv1 = lv_tileview_add_tile(dis, 0, 0, LV_DIR_VER);
    
    state_symbol = lv_label_create(lv_scr_act());
    lv_obj_align(state_symbol, LV_ALIGN_TOP_LEFT, 20, 5);
    lv_obj_set_width(state_symbol, LV_PCT(80));
    lv_label_set_long_mode(state_symbol, LV_LABEL_LONG_SCROLL);
    lv_label_set_recolor(state_symbol, true);

    img1 = lv_gif_create(tv1);
    img2 = lv_gif_create(tv1);
    img3 = lv_gif_create(tv1);
    img4 = lv_gif_create(tv1);
    img5 = lv_gif_create(tv1);
    img6 = lv_gif_create(tv1);

    lv_gif_set_src(img1, set_anim_src(9));
    lv_gif_set_src(img2, set_anim_src(9));
    lv_gif_set_src(img3, set_anim_src(9));
    lv_gif_set_src(img4, set_anim_src(9));
    lv_gif_set_src(img5, set_anim_src(9));
    lv_gif_set_src(img6, set_anim_src(9));

    lv_obj_align(img1, LV_ALIGN_LEFT_MID, 20, 0);
    lv_obj_align_to(img2, img1, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
    lv_obj_align(img3, LV_ALIGN_LEFT_MID, 225, 0);
    lv_obj_align_to(img4, img3, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
    lv_obj_align(img5, LV_ALIGN_LEFT_MID, 430, 0);
    lv_obj_align_to(img6, img5, LV_ALIGN_OUT_RIGHT_MID, 0, 0);

    lv_msg_subsribe(MSG_NEW_HOUR, update_text_subscriber_cb_demo1, NULL);
    lv_msg_subsribe(MSG_NEW_MIN, update_text_subscriber_cb_demo1, NULL);
    lv_msg_subsribe(MSG_NEW_SEC, update_text_subscriber_cb_demo1, NULL);
    lv_msg_subsribe(MSG_NEW_VOLT, update_display_state, NULL);
}

static void update_display_state(void *s, lv_msg_t *msg) {
    const char * payload = (const char *)lv_msg_get_payload(msg);

    if (lv_msg_get_id(msg) == MSG_NEW_VOLT) {
        if (payload == "0") {
            lv_label_set_text(state_symbol, "#00FF00 " LV_SYMBOL_OK "  ON #");
        } else if (payload == "1") {
            lv_label_set_text(state_symbol, "#FFA500 " LV_SYMBOL_PAUSE "  IDLE #");
        } else if (payload == "2") {
            lv_label_set_text(state_symbol, "#FF0000 " LV_SYMBOL_POWER"  OFF #");
        } else {
            lv_label_set_text(state_symbol, "");
        }
    }
}

static void update_text_subscriber_cb_demo1(void *s, lv_msg_t *msg) {
    static int      hour       = 0;
    static int      minute     = 0;
    static int      second     = 0;
    static uint32_t start_tick = lv_tick_get();
    const int32_t  *v          = (const int32_t *)lv_msg_get_payload(msg);

    /* clang-format off */
    switch (lv_msg_get_id(msg)) {
    case MSG_NEW_HOUR: hour = *v;   break;
    case MSG_NEW_MIN:  minute = *v; break;
    case MSG_NEW_SEC:  second = *v; break;
    default:
        break;
    } /* clang-format off */

    if (lv_tick_elaps(start_tick) >= 1000) {
        start_tick = lv_tick_get();
        set_flip_time_anim(hour, minute, second);
    }
}

void set_flip_time_anim(int hour, int minute, int second) {
    static int sec_h, sec_l, min_h, min_l, hou_h, hou_l;

    timer_l(sec_l, second, img6);
    timer_h(sec_h, second, img5);
    timer_l(min_l, minute, img4);
    timer_h(min_h, minute, img3);
    timer_l(hou_l, hour, img2);
    timer_h(hou_h, hour, img1);

    // printf("clock=%02d:%02d:%02d\n", hour, minute, second);
}

void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
  uint32_t w = (area->x2 - area->x1 + 1);
  uint32_t h = (area->y2 - area->y1 + 1);

  #ifdef LCD_SPI_DMA
      char i = 0;
      while (get_lcd_spi_dma_write()) {
          i = i >> 1;
          lcd_PushColors(0, 0, 0, 0, NULL);
      }
  #endif
      lcd_PushColors(area->x1, area->y1, w, h, (uint16_t *)&color_p->full);

  #ifdef LCD_SPI_DMA

  #else
      lv_disp_flush_ready(disp);
  #endif
}

void lv_delay_ms(int x) {
    do {
        uint32_t t = x;
        while (t--) {
            delay(1);
            if (transfer_num <= 0 && lcd_PushColors_len <= 0)
                lv_timer_handler();

            if (transfer_num <= 1 && lcd_PushColors_len > 0) {
                lcd_PushColors(0, 0, 0, 0, NULL);
            }
        }
    } while (0);
}
