#include <furi.h>
#include <gui/elements.h>
#include <assets_icons.h>
#include <momentum/momentum.h>
#include <furi_hal_rtc.h>

#include "../desktop_i.h"
#include "desktop_view_lock_menu.h"

static const NotificationSequence sequence_note_c = {
    &message_note_c5,
    &message_delay_100,
    &message_sound_off,
    NULL,
};

typedef enum {
    DesktopLockMenuIndexLefthandedMode,
    DesktopLockMenuIndexSettings,
    DesktopLockMenuIndexDarkMode,
    DesktopLockMenuIndexLock,
    DesktopLockMenuIndexBluetooth,
    DesktopLockMenuIndexMomentum,
    DesktopLockMenuIndexBrightness,
    DesktopLockMenuIndexVolume,

    DesktopLockMenuIndexTotalCount
} DesktopLockMenuIndex;

void desktop_lock_menu_set_callback(
    DesktopLockMenuView* lock_menu,
    DesktopLockMenuViewCallback callback,
    void* context) {
    furi_assert(lock_menu);
    furi_assert(callback);
    lock_menu->callback = callback;
    lock_menu->context = context;
}

void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is_set) {
    with_view_model(
        lock_menu->view,
        DesktopLockMenuViewModel * model,
        {
            model->pin_is_set = pin_is_set;
            model->lock_popup_index = pin_is_set; // Select with PIN by default if set
        },
        true);
}

void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bool stealth_mode) {
    with_view_model(
        lock_menu->view,
        DesktopLockMenuViewModel * model,
        { model->stealth_mode = stealth_mode; },
        true);
}

void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) {
    furi_assert(idx < DesktopLockMenuIndexTotalCount);
    with_view_model(
        lock_menu->view, DesktopLockMenuViewModel * model, { model->idx = idx; }, true);
}

void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) {
    DesktopLockMenuViewModel* m = model;

    canvas_set_color(canvas, ColorBlack);
    canvas_set_font(canvas, FontBatteryPercent);

    int8_t x, y, w, h;
    bool selected, toggle;
    bool enabled = false;
    uint8_t value = 0;
    int8_t total = 58;
    const Icon* icon = NULL;
    for(size_t i = 0; i < DesktopLockMenuIndexTotalCount; ++i) {
        selected = m->idx == i;
        toggle = i < 6;
        if(toggle) {
            x = 2 + 32 * (i / 2);
            y = 2 + 32 * (i % 2);
            w = 28;
            h = 28;
            enabled = false;
        } else {
            x = 98 + 16 * (i % 2);
            y = 2;
            w = 12;
            h = 60;
            value = 0;
        }

        switch(i) {
        case DesktopLockMenuIndexLefthandedMode:
            icon = &I_CC_LefthandedMode_16x16;
            enabled = furi_hal_rtc_is_flag_set(FuriHalRtcFlagHandOrient);
            break;
        case DesktopLockMenuIndexSettings:
            icon = &I_CC_Settings_16x16;
            break;
        case DesktopLockMenuIndexDarkMode:
            icon = &I_CC_DarkMode_16x16;
            enabled = momentum_settings.dark_mode;
            break;
        case DesktopLockMenuIndexLock:
            icon = &I_CC_Lock_16x16;
            break;
        case DesktopLockMenuIndexBluetooth:
            icon = &I_CC_Bluetooth_16x16;
            enabled = m->lock_menu->bt->bt_settings.enabled;
            break;
        case DesktopLockMenuIndexMomentum:
            icon = &I_CC_Momentum_16x16;
            break;
        case DesktopLockMenuIndexBrightness:
            icon = &I_Pin_star_7x7;
            value = total - m->lock_menu->notification->settings.display_brightness * total;
            break;
        case DesktopLockMenuIndexVolume:
            icon = m->stealth_mode ? &I_Muted_8x8 : &I_Volup_8x6;
            value = total - m->lock_menu->notification->settings.speaker_volume * total;
            break;
        default:
            break;
        }

        if(selected) {
            elements_bold_rounded_frame(canvas, x - 1, y - 1, w + 1, h + 1);
        } else {
            canvas_draw_rframe(canvas, x, y, w, h, 5);
        }

        if(toggle) {
            if(enabled) {
                canvas_draw_rbox(canvas, x, y, w, h, 5);
                canvas_set_color(canvas, ColorWhite);
            }
            canvas_draw_icon(
                canvas,
                x + (w - icon_get_width(icon)) / 2,
                y + (h - icon_get_height(icon)) / 2,
                icon);
            if(enabled) {
                canvas_set_color(canvas, ColorBlack);
            }
        } else {
            canvas_draw_icon(
                canvas,
                x + (w - icon_get_width(icon)) / 2,
                y + (h - icon_get_height(icon)) / 2,
                icon);
            canvas_set_color(canvas, ColorXOR);
            canvas_draw_box(canvas, x + 1, y + 1 + value, w - 2, h - 2 - value);
            if(selected) {
                canvas_set_color(canvas, ColorBlack);
            } else {
                canvas_set_color(canvas, ColorWhite);
            }
            canvas_draw_dot(canvas, x + 1, y + 1);
            canvas_draw_dot(canvas, x + 1, y + h - 2);
            canvas_draw_dot(canvas, x + w - 2, y + 1);
            canvas_draw_dot(canvas, x + w - 2, y + h - 2);
            canvas_set_color(canvas, ColorBlack);
            canvas_draw_rframe(canvas, x, y, w, h, 5);
        }
    }

    if(m->show_lock_popup) {
        if(momentum_settings.popup_overlay) {
            canvas_draw_overlay(canvas);
        }
        canvas_set_font(canvas, FontSecondary);
        elements_bold_rounded_frame(canvas, 24, 4, 80, 56);
        canvas_draw_str_aligned(canvas, 64, 16, AlignCenter, AlignCenter, "Keypad Lock");
        canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, "PIN Code Lock");
        canvas_draw_str_aligned(canvas, 64, 48, AlignCenter, AlignCenter, "PIN Lock + OFF");
        elements_frame(canvas, 28, 8 + m->lock_popup_index * 16, 72, 15);
    }
}

View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu) {
    furi_assert(lock_menu);
    return lock_menu->view;
}

bool desktop_lock_menu_input_callback(InputEvent* event, void* context) {
    furi_assert(event);
    furi_assert(context);

    DesktopLockMenuView* lock_menu = context;
    uint8_t idx = 0;
    bool show_lock_popup = false;
    DesktopLockMenuPopupIndex lock_popup_index = 0;
    bool stealth_mode = false;
    bool consumed = true;

    with_view_model(
        lock_menu->view,
        DesktopLockMenuViewModel * model,
        {
            show_lock_popup = model->show_lock_popup;
            stealth_mode = model->stealth_mode;
            if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) {
                if(model->show_lock_popup) {
                    if(event->key == InputKeyUp) {
                        if(model->lock_popup_index == 0) {
                            model->lock_popup_index = DesktopLockMenuPopupIndexMAX - 1;
                        } else {
                            model->lock_popup_index--;
                        }
                    } else if(event->key == InputKeyDown) {
                        if(model->lock_popup_index == DesktopLockMenuPopupIndexMAX - 1) {
                            model->lock_popup_index = 0;
                        } else {
                            model->lock_popup_index++;
                        }
                    } else if(event->key == InputKeyBack || event->key == InputKeyOk) {
                        model->show_lock_popup = false;
                    }
                } else {
                    if(model->idx == DesktopLockMenuIndexLock && event->key == InputKeyOk) {
                        model->show_lock_popup = true;
                    } else if(model->idx < 6) {
                        if(event->key == InputKeyUp || event->key == InputKeyDown) {
                            if(model->idx % 2) {
                                model->idx--;
                            } else {
                                model->idx++;
                            }
                        } else if(event->key == InputKeyLeft) {
                            if(model->idx < 2) {
                                model->idx = 7;
                            } else {
                                model->idx -= 2;
                            }
                        } else if(event->key == InputKeyRight) {
                            if(model->idx >= 4) {
                                model->idx = 6;
                            } else {
                                model->idx += 2;
                            }
                        }
                    } else {
                        if(event->key == InputKeyLeft) {
                            model->idx--;
                        } else if(event->key == InputKeyRight) {
                            if(model->idx >= 7) {
                                model->idx = 1;
                            } else {
                                model->idx++;
                            }
                        }
                    }
                }
            }
            idx = model->idx;
            lock_popup_index = model->lock_popup_index;
        },
        true);

    DesktopEvent desktop_event = 0;
    if(show_lock_popup) {
        if(event->key == InputKeyOk && event->type == InputTypeShort) {
            switch(lock_popup_index) {
            case DesktopLockMenuPopupIndexKeypad:
                desktop_event = DesktopLockMenuEventLockKeypad;
                break;
            case DesktopLockMenuPopupIndexPinCode:
                desktop_event = DesktopLockMenuEventLockPinCode;
                break;
            case DesktopLockMenuPopupIndexPinOff:
                desktop_event = DesktopLockMenuEventLockPinOff;
                break;
            default:
                break;
            }
        }
    } else {
        if(event->key == InputKeyBack) {
            consumed = false;
        } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
            switch(idx) {
            case DesktopLockMenuIndexLefthandedMode:
                if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagHandOrient)) {
                    furi_hal_rtc_reset_flag(FuriHalRtcFlagHandOrient);
                } else {
                    furi_hal_rtc_set_flag(FuriHalRtcFlagHandOrient);
                }
                break;
            case DesktopLockMenuIndexSettings:
                desktop_event = DesktopLockMenuEventSettings;
                break;
            case DesktopLockMenuIndexDarkMode:
                momentum_settings.dark_mode = !momentum_settings.dark_mode;
                lock_menu->save_momentum = true;
                break;
            case DesktopLockMenuIndexBluetooth:
                lock_menu->bt->bt_settings.enabled = !lock_menu->bt->bt_settings.enabled;
                if(lock_menu->bt->bt_settings.enabled) {
                    furi_hal_bt_start_advertising();
                } else {
                    furi_hal_bt_stop_advertising();
                }
                lock_menu->save_bt = true;
                break;
            case DesktopLockMenuIndexMomentum:
                desktop_event = DesktopLockMenuEventMomentum;
                break;
            case DesktopLockMenuIndexBrightness:
                desktop_event = DesktopLockMenuEventScreenSettings;
                break;
            case DesktopLockMenuIndexVolume:
                desktop_event = stealth_mode ? DesktopLockMenuEventStealthModeOff :
                                               DesktopLockMenuEventStealthModeOn;
                break;
            default:
                break;
            }
        } else if(idx >= 6 && (event->type == InputTypeShort || event->type == InputTypeRepeat)) {
            int8_t offset = 0;
            if(event->key == InputKeyUp) {
                offset = 1;
            } else if(event->key == InputKeyDown) {
                offset = -1;
            }
            if(offset) {
                float value;
                switch(idx) {
                case DesktopLockMenuIndexBrightness:
                    value = lock_menu->notification->settings.display_brightness + 0.05 * offset;
                    lock_menu->notification->settings.display_brightness =
                        value < 0.00f ? 0.00f : (value > 1.00f ? 1.00f : value);
                    lock_menu->save_notification = true;
                    notification_message(lock_menu->notification, &sequence_display_backlight_on);
                    break;
                case DesktopLockMenuIndexVolume:
                    value = lock_menu->notification->settings.speaker_volume + 0.05 * offset;
                    lock_menu->notification->settings.speaker_volume =
                        value < 0.00f ? 0.00f : (value > 1.00f ? 1.00f : value);
                    lock_menu->save_notification = true;
                    notification_message(lock_menu->notification, &sequence_note_c);
                    break;
                default:
                    break;
                }
            }
        }
    }
    if(desktop_event) {
        lock_menu->callback(desktop_event, lock_menu->context);
    }

    return consumed;
}

DesktopLockMenuView* desktop_lock_menu_alloc(void) {
    DesktopLockMenuView* lock_menu = malloc(sizeof(DesktopLockMenuView));
    lock_menu->bt = furi_record_open(RECORD_BT);
    lock_menu->notification = furi_record_open(RECORD_NOTIFICATION);
    lock_menu->view = view_alloc();
    view_allocate_model(lock_menu->view, ViewModelTypeLocking, sizeof(DesktopLockMenuViewModel));
    with_view_model(
        lock_menu->view,
        DesktopLockMenuViewModel * model,
        { model->lock_menu = lock_menu; },
        false);
    view_set_context(lock_menu->view, lock_menu);
    view_set_draw_callback(lock_menu->view, (ViewDrawCallback)desktop_lock_menu_draw_callback);
    view_set_input_callback(lock_menu->view, desktop_lock_menu_input_callback);

    return lock_menu;
}

void desktop_lock_menu_free(DesktopLockMenuView* lock_menu_view) {
    furi_assert(lock_menu_view);

    view_free(lock_menu_view->view);
    furi_record_close(RECORD_NOTIFICATION);
    furi_record_close(RECORD_BT);
    free(lock_menu_view);
}
