#include <stdint.h>
#include "keypad.h"
#include "st7735.h"
#include "asciifont.h"
#include "ui_menu.h"
#include "ui_utils.h"

#define LIST_STYLE_SELECTED_COLOR_BG ST7735_COLOR565(0x40, 0x40, 0x40)
#define LIST_STYLE_OFFSET_LEFT 32
#define UI_HALF_Y (UI_Y + (UI_H / 2))
#define LIST_PAGE_SIZE (UI_H / font_unifont_8x16->char_height)
#define LIST_PAGE_SIZE_HALF ((LIST_PAGE_SIZE + 1) / 2)
#define LIST_ITEM_LEVEL(p) ((p < LIST_PAGE_SIZE_HALF) ? (p) : (LIST_PAGE_SIZE - p - 1))
#define UI_LIST_OFFSET_X(p) (UI_X + (LIST_STYLE_OFFSET_LEFT * LIST_ITEM_LEVEL(p) / (LIST_PAGE_SIZE_HALF - 1)) + 8)
#define UI_LIST_OFFSET_Y(p) (UI_Y + (font_unifont_8x16->char_height * p))
#define UI_LIST_WIDTH(p) (UI_W - (LIST_STYLE_OFFSET_LEFT * LIST_ITEM_LEVEL(p) / (LIST_PAGE_SIZE_HALF - 1)) - 8)

#define U8_RESET 255
/*
0
 1
  2
   3
    4
   5
  6
 7
8
*/
static uint16_t get_item_count(uiu_GetStrItemFunc get_item) {
    uint16_t len = 0;
    while (get_item(len).len > 0) {
        len ++;
    }
    return len;
}

static void render_page_number(uint8_t curr, uint8_t total) {
    uint8_t number_str[4] = {0, 0, 0, 0};
    uint8_t scale = 100;
    uint8_t num_pos = 0;
    while (scale > 0) {
        uint8_t num = (curr / scale) % 10;
        scale /= 10;
        if (num == 0 && num_pos == 0) continue;
        number_str[num_pos] = '0' + num;
        num_pos ++;
    }
    uiu_text_area(font_quan_8x8, number_str, 4,
        UI_X, UI_HALF_Y - 1 - font_quan_8x8->char_height - 1,
        font_quan_8x8->char_width * 3, font_quan_8x8->char_height,
        uiu_ALIGN_HCENTER | uiu_ALIGN_VCENTER, ST7735_YELLOW, ST7735_BLACK
    );
    number_str[0] = 0;
    number_str[1] = 0;
    number_str[2] = 0;
    number_str[3] = 0;
    scale = 100;
    num_pos = 0;
    while (scale > 0) {
        uint8_t num = (total / scale) % 10;
        scale /= 10;
        if (num == 0 && num_pos == 0) continue;
        number_str[num_pos] = '0' + num;
        num_pos ++;
    }
    uiu_text_area(font_quan_8x8, number_str, 4,
        UI_X, UI_HALF_Y + 2,
        font_quan_8x8->char_width * 3, font_quan_8x8->char_height,
        uiu_ALIGN_HCENTER | uiu_ALIGN_VCENTER, ST7735_YELLOW, ST7735_BLACK
    );
}

IndexResult iui_list_select(const uint8_t *title, uint32_t len, uiu_GetStrItemFunc get_item, uint16_t init_index) {
    uint16_t item_count = get_item_count(get_item);
    uint16_t pointer = init_index % item_count;
    uint8_t tmp_pointer = U8_RESET;
    uint8_t last_pointer = U8_RESET;
    uint16_t page_start = (pointer / LIST_PAGE_SIZE) * LIST_PAGE_SIZE;
    printf("item count: %u\n", item_count);
    // clear
    ST7735_FillScreen(ST7735_BLACK);
    // render title
    uiu_title(title, len);
    // render line
    ST7735_DrawLine(UI_X, UI_Y + font_unifont_8x16->char_height, LIST_STYLE_OFFSET_LEFT - 1, UI_HALF_Y - 1, ST7735_YELLOW);
    ST7735_DrawLine(UI_X, UI_Y + UI_H - font_unifont_8x16->char_height - 1, LIST_STYLE_OFFSET_LEFT - 1, UI_HALF_Y, ST7735_YELLOW);
    ST7735_FillRectangle(UI_X, UI_HALF_Y - 1, LIST_STYLE_OFFSET_LEFT - 1, 1, ST7735_YELLOW);
    while (1) {
        uint8_t event = kp_query();
        uint8_t et = kp_Type(event);
        uint8_t ev = kp_Value(event);
        // process event
        if (et == kp_ROTATE_RIGHT || et == kp_ROTATE_LEFT) {
            if (et == kp_ROTATE_RIGHT) {
                pointer += ev;
            } else {
                pointer += (0x7FFF / item_count) * item_count;
                pointer -= ev;
            }
            pointer %= item_count;
            if (((pointer / LIST_PAGE_SIZE) * LIST_PAGE_SIZE) != page_start) {
                last_pointer = U8_RESET;
                page_start = ((pointer / LIST_PAGE_SIZE) * LIST_PAGE_SIZE);
            }
            tmp_pointer = U8_RESET;
            printf("Move list pointer to %u\n", pointer);
        } else if (et == kp_SHORT_CLICK) {
            if (ev == kp_KEYENCODER) {
                discare_kp_events();
                printf("Confirm list item %u\n", pointer);
                IndexResult ret = {pointer, 1};
                return ret;
            }
        } else if (et == kp_LONG_PRESS) {
            if (ev == kp_KEYENCODER) {
                discare_kp_events();
                printf("Cancel list item %u\n", pointer);
                IndexResult ret = {pointer, 0};
                return ret;
            }
        } else if (et != kp_NOP) {
            printf("Unhandled event: %u %u\n", et, ev);
        }
        // render items
        if (tmp_pointer == U8_RESET) {
            // need render
            if (last_pointer == U8_RESET) {
                // render all
                render_page_number((pointer / LIST_PAGE_SIZE) + 1, (item_count + LIST_PAGE_SIZE - 1) / LIST_PAGE_SIZE);
                for (tmp_pointer = 0; tmp_pointer < LIST_PAGE_SIZE; tmp_pointer ++) {
                    uint16_t current = page_start + tmp_pointer;
                    if (current >= item_count) {
                        uiu_text_area(font_unifont_8x16, u8str(" "), 1,
                            UI_LIST_OFFSET_X(tmp_pointer), UI_LIST_OFFSET_Y(tmp_pointer),
                            UI_LIST_WIDTH(tmp_pointer), font_unifont_8x16->char_height,
                            uiu_ALIGN_HCENTER | uiu_ALIGN_VCENTER, ST7735_WHITE, ST7735_BLACK
                        );
                        continue;
                    }
                    StrItem item = get_item(current);
                    if (current == pointer) {
                        uiu_text_area(font_unifont_8x16, item.text, item.len,
                            UI_LIST_OFFSET_X(tmp_pointer), UI_LIST_OFFSET_Y(tmp_pointer),
                            UI_LIST_WIDTH(tmp_pointer), font_unifont_8x16->char_height,
                            uiu_ALIGN_HCENTER | uiu_ALIGN_VCENTER, ST7735_GREEN, LIST_STYLE_SELECTED_COLOR_BG
                        );
                        last_pointer = tmp_pointer;
                    } else {
                        uiu_text_area(font_unifont_8x16, item.text, item.len,
                            UI_LIST_OFFSET_X(tmp_pointer), UI_LIST_OFFSET_Y(tmp_pointer),
                            UI_LIST_WIDTH(tmp_pointer), font_unifont_8x16->char_height,
                            uiu_ALIGN_HCENTER | uiu_ALIGN_VCENTER, ST7735_WHITE, ST7735_BLACK
                        );
                    }
                }
            } else {
                StrItem item = get_item(page_start + last_pointer);
                uiu_text_area(font_unifont_8x16, item.text, item.len,
                    UI_LIST_OFFSET_X(last_pointer), UI_LIST_OFFSET_Y(last_pointer),
                    UI_LIST_WIDTH(last_pointer), font_unifont_8x16->char_height,
                    uiu_ALIGN_HCENTER | uiu_ALIGN_VCENTER, ST7735_WHITE, ST7735_BLACK
                );
                last_pointer = pointer - page_start;
                StrItem item_curr = get_item(pointer);
                uiu_text_area(font_unifont_8x16, item_curr.text, item_curr.len,
                    UI_LIST_OFFSET_X(last_pointer), UI_LIST_OFFSET_Y(last_pointer),
                    UI_LIST_WIDTH(last_pointer), font_unifont_8x16->char_height,
                    uiu_ALIGN_HCENTER | uiu_ALIGN_VCENTER, ST7735_GREEN, LIST_STYLE_SELECTED_COLOR_BG
                );
            }
            tmp_pointer = 0;
        }
    }
}
