/*********************
 *      INCLUDES
 *********************/
#include <esp_log.h>
#include <string>
#include "message_queue.hpp"
#include "gui.h"

#if LV_MEM_CUSTOM == 0 && LV_MEM_SIZE < (38ul * 1024ul)
    #error Insufficient memory for lv_demo_widgets. Please set LV_MEM_SIZE to at least 38KB (38ul * 1024ul).  48KB is recommended.
#endif

extern const lv_font_t Franklin_18_rus;
extern const lv_font_t Franklin_24_rus;
extern const lv_font_t Franklin_36_rus;
extern const lv_font_t Franklin_48_rus;
extern const lv_font_t Impact_48;
extern const lv_font_t Impact_72;
extern const lv_font_t Impact_96;

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/
typedef enum {
    DISP_SMALL,
    DISP_MEDIUM,
    DISP_LARGE,
} disp_size_t;

const size_t MAX_MESSAGE_LENGTH = 128;
using message_t = std::array<char, MAX_MESSAGE_LENGTH>;
MessageQueue messages = MessageQueue<message_t, 16>();

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void profile_create(lv_obj_t * parent);
static void analytics_create(lv_obj_t * parent);

static lv_obj_t * create_meter_box(lv_obj_t * parent, const char * title, const char * text1, const char * text2,
                                   const char * text3);

static void ta_event_cb(lv_event_t * e);
static void birthday_event_cb(lv_event_t * e);
static void chart_event_cb(lv_event_t * e);
static void meter1_indic1_anim_cb(void * var, int32_t v);
static void meter1_indic2_anim_cb(void * var, int32_t v);
static void meter1_indic3_anim_cb(void * var, int32_t v);
static void meter2_timer_cb(lv_timer_t * timer);
static void meter3_anim_cb(void * var, int32_t v);

/**********************
 *  STATIC VARIABLES
 **********************/
static disp_size_t disp_size;

static lv_obj_t * tv;
static lv_obj_t * calendar;
static lv_style_t style_text_white;
static lv_style_t style_title;
static lv_style_t style_big_num;
static lv_style_t style_icon;
static lv_style_t style_bullet;

static lv_obj_t * name;
static lv_obj_t * balance;
static lv_obj_t * unit;
static lv_obj_t * message_text;
static lv_obj_t * panel_error;

static const lv_font_t * font_large;
static const lv_font_t * font_normal;
static const lv_font_t * font_small;
static const lv_font_t * font_num;

static uint32_t session_desktop = 1000;
static uint32_t session_tablet = 1000;
static uint32_t session_mobile = 1000;

static const char *TAG = "gui";

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

void gui_init()
{
    if(LV_HOR_RES <= 320) disp_size = DISP_SMALL;
    else if(LV_HOR_RES < 720) disp_size = DISP_MEDIUM;
    else disp_size = DISP_LARGE;

    lv_coord_t tab_h;
    if(disp_size == DISP_LARGE) {
        ESP_LOGI(TAG, "Display size: large");
        tab_h = 70;
        font_large = &Franklin_48_rus;
        font_normal = &Franklin_36_rus;
        font_small = &Franklin_24_rus;
        font_num = &Impact_96;
    }
    else if(disp_size == DISP_MEDIUM) {
        ESP_LOGI(TAG, "Display size: medium");
        tab_h = 45;
        font_large = &Franklin_48_rus;
        font_normal = &Franklin_36_rus;
        font_small = &Franklin_24_rus;
        font_num = &Impact_96;
    }
    else {
        ESP_LOGI(TAG, "Display size: small");
        tab_h = 45;
        font_large = &Franklin_36_rus;
        font_normal = &Franklin_24_rus;
        font_small = &Franklin_18_rus;
        font_num = &Impact_48;
    }

#if LV_USE_THEME_DEFAULT
    lv_theme_default_init(NULL, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), LV_THEME_DEFAULT_DARK, font_normal);
#endif

    lv_style_init(&style_text_white);
    lv_style_set_text_font(&style_title, font_normal);
    lv_style_set_text_color(&style_title, lv_color_hex(0xFFFFFF));

    lv_style_init(&style_title);
    lv_style_set_text_font(&style_title, font_large);
    lv_style_set_text_color(&style_title, lv_color_hex(0xFFFFFF));

    lv_style_init(&style_big_num);
    lv_style_set_text_font(&style_big_num, font_num);
    lv_style_set_text_color(&style_big_num, lv_color_hex(0xFFFFFF));

    lv_obj_set_style_text_font(lv_scr_act(), font_normal, 0);
    lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(0x00003F), 0);
    lv_obj_set_flex_flow(lv_scr_act(), LV_FLEX_FLOW_COLUMN);
    lv_obj_clear_flag(lv_scr_act(), LV_OBJ_FLAG_SCROLLABLE);

    lv_obj_t * parent = lv_scr_act();

    lv_obj_t * panel_balance = lv_obj_create(parent);
    lv_obj_set_width(panel_balance, LV_PCT(100));
    lv_obj_set_height(panel_balance, LV_SIZE_CONTENT);
    lv_obj_set_style_bg_color(panel_balance, lv_color_hex(0x000000), 0);
    lv_obj_set_style_border_width(panel_balance, 4, 0);
    lv_obj_set_style_border_color(panel_balance, lv_color_hex(0x0000FF), 0);
    lv_obj_clear_flag(panel_balance, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_update_layout(panel_balance);

    name = lv_label_create(panel_balance);
    lv_label_set_text(name, "Баланс");
    lv_obj_align(name, LV_ALIGN_LEFT_MID, 0, 0);
    lv_obj_set_pos(name, 0, 30);
    lv_obj_add_style(name, &style_text_white, 0);

    balance = lv_label_create(panel_balance);
    lv_label_set_text(balance, "0");
    lv_obj_add_style(balance, &style_big_num, 0);
    lv_obj_align(balance, LV_ALIGN_CENTER, 0, 0);
    lv_obj_set_pos(name, 0, 0);
    lv_obj_set_style_text_align(balance, LV_TEXT_ALIGN_CENTER, 0);

    unit = lv_label_create(panel_balance);
    lv_label_set_text(unit, "рублей");
    //lv_obj_update_layout(balance);
    lv_obj_add_style(unit, &style_text_white, 0);
    //lv_obj_set_width(unit, (uint32_t)panel_width * 25 / 100);
    lv_obj_align(unit, LV_ALIGN_RIGHT_MID, 0, 0);
    lv_obj_set_pos(unit, 0, 30);
    //lv_obj_set_style_text_align(unit, LV_TEXT_ALIGN_RIGHT, 0);
    lv_obj_set_style_border_color(unit, lv_color_hex(0x00FF00), 0);

    lv_obj_update_layout(balance);
    lv_coord_t balance_height = lv_obj_get_height(balance);
    lv_obj_set_height(name, balance_height);
    lv_obj_align(name, LV_ALIGN_LEFT_MID, 0, 0);
    lv_obj_set_height(unit, balance_height);
    ESP_LOGI(TAG, "height %d", balance_height);

    /*lv_obj_t * panel_info = lv_obj_create(parent);
    lv_obj_set_width(panel_info, LV_PCT(100));
    lv_obj_set_height(panel_info, LV_SIZE_CONTENT);
    lv_obj_set_style_bg_color(panel_info, lv_color_hex(0x00001F), 0);
    lv_obj_set_style_border_width(panel_info, 4, 0);
    lv_obj_set_style_border_color(panel_info, lv_color_hex(0x0000FF), 0);*/

    message_text = lv_label_create(parent);
    lv_label_set_text(message_text, "");
    lv_label_set_long_mode(message_text, LV_LABEL_LONG_WRAP);
    lv_obj_set_width(message_text, LV_PCT(100));
    lv_obj_set_style_pad_left(message_text, 8, 0);
    lv_obj_set_style_pad_right(message_text, 8, 0);

    panel_error = lv_obj_create(lv_layer_top());
    lv_obj_set_width(panel_error, LV_PCT(100));
    lv_obj_set_height(panel_error, LV_PCT(100));

    lv_obj_set_style_bg_color(panel_error, lv_color_hex(0x1F0000), 0);
    lv_obj_set_style_border_width(panel_error, 4, 0);
    lv_obj_set_style_border_color(panel_error, lv_color_hex(0xFF0000), 0);
    lv_obj_clear_flag(panel_error, LV_OBJ_FLAG_SCROLLABLE);

    lv_obj_t * text_error = lv_label_create(panel_error);
    lv_label_set_text(text_error, "Аппарат\nнеисправен");
    lv_obj_add_style(text_error, &style_title, 0);
    lv_obj_align(text_error, LV_ALIGN_CENTER, 0, 0);
    lv_obj_set_style_text_align(text_error, LV_TEXT_ALIGN_CENTER, 0);
    lv_label_set_long_mode(message_text, LV_LABEL_LONG_WRAP);
}

void gui_balance(float value)
{
    int digit = 2;
    if ((int)(value * 100) % 100 == 0)
        digit = 0;
    else if ((int)(value * 100) % 10 == 0)
        digit = 1;

    char buf[32] = "";
    snprintf(buf, 31, "%.*f", digit, value);
    lv_label_set_text(balance, buf);

    int last_digit = (int)value % 10;
    switch (last_digit) {
        case 1:
            lv_label_set_text(unit, "рубль");
            break;
        case 2:
        case 3:
        case 4:
            lv_label_set_text(unit, "рубля");
            break;
        default:
            lv_label_set_text(unit, "рублей");
    }
}

void gui_update()
{
    unsigned int updated = millis() - Info.Updated;
    if (updated < 5000)
        lv_obj_add_flag(panel_error, LV_OBJ_FLAG_HIDDEN);
    else
        lv_obj_clear_flag(panel_error, LV_OBJ_FLAG_HIDDEN);
    if (Info.Credit < 1.0) {
        lv_label_set_text(name, "Цена\nлитра");
        gui_balance(Info.Price);
    } else {
        lv_label_set_text(name, "Баланс");
        gui_balance((int)Info.Credit);
    }
    message_t* msg = messages.get();
    if (msg) {
        lv_label_set_text(message_text, (*msg).begin());
        lv_label_set_long_mode(message_text, LV_LABEL_LONG_WRAP);
    } else {
        if (Info.Credit < 1.0) {
            lv_label_set_text(message_text, "Внесите предоплату или нажмите кнопку объема для оплаты картой");
            lv_label_set_long_mode(message_text, LV_LABEL_LONG_WRAP);
        } else {
            float credit_liters = Info.Credit / Info.Price;
            int digit = 2;
            if ((int)(credit_liters * 100) % 100 == 0)
                digit = 0;
            else if ((int)(credit_liters * 100) % 10 == 0)
                digit = 1;
            char buf[32] = "";
            snprintf(buf, 31, "Хватит на %.*f л", digit, credit_liters);
            lv_label_set_text(message_text, buf);
        }
    }
}

void gui_add_message(const char text[], int timeout)
{
    message_t msg {};
    std::copy_n(text, MAX_MESSAGE_LENGTH, msg.begin());
    messages.add(msg, timeout);
}