#include "../minesweeper.h"
#include "../views/minesweeper_game_screen.h"

typedef enum {
    MineSweeperSettingsScreenDifficultyTypeEasy,
    MineSweeperSettingsScreenDifficultyTypeMedium,
    MineSweeperSettingsScreenDifficultyTypeHard,
    MineSweeperSettingsScreenDifficultyTypeNum,
} MineSweeperSettingsScreenDifficultyType;

typedef enum {
    MineSweeperSettingsScreenIndexDifficulty,
    MineSweeperSettingsScreenIndexWidth,
    MineSweeperSettingsScreenIndexHeight,
    MineSweeperSettingsScreenIndexNum,
} MineSweeperSettingsScreenIndex;

typedef enum {
    MineSweeperSettingsScreenEventDifficultyChange,
    MineSweeperSettingsScreenEventWidthChange,
    MineSweeperSettingsScreenEventHeightChange,
    MineSweeperSettingsScreenEventSolvableChange,
    MineSweeperSettingsScreenEventInfoChange,
    MineSweeperSettingsScreenEventFeedbackChange,
} MineSweeperSettingsScreenEvent;

static const char* settings_screen_difficulty_text[MineSweeperSettingsScreenDifficultyTypeNum] = {
    "Easy",
    "Medium",
    "Hard",
};

static const char* settings_screen_verifier_text[2] = {
    "False",
    "True",
};

static void minesweeper_scene_settings_screen_set_difficulty(VariableItem* item) {
    furi_assert(item);

    MineSweeperApp* app = variable_item_get_context(item);
    app->t_settings_info.difficulty_item = item;

    uint8_t index = variable_item_get_current_value_index(app->t_settings_info.difficulty_item);

    app->t_settings_info.difficulty = index;

    variable_item_set_current_value_text(
        app->t_settings_info.difficulty_item, settings_screen_difficulty_text[index]);

    view_dispatcher_send_custom_event(
        app->view_dispatcher, MineSweeperSettingsScreenEventDifficultyChange);
}

static void minesweeper_scene_settings_screen_set_width(VariableItem* item) {
    char source[5];
    uint8_t index = 0;
    uint8_t curr_board_height = 7;
    bool is_over_max_tiles = false;

    furi_assert(item);

    MineSweeperApp* app = variable_item_get_context(item);
    app->t_settings_info.width_item = item;

    index = variable_item_get_current_value_index(app->t_settings_info.width_item);
    app->t_settings_info.board_width = index + 16;

    curr_board_height = app->t_settings_info.board_height;

    is_over_max_tiles = (app->t_settings_info.board_width * curr_board_height) >
                        MINESWEEPER_BOARD_MAX_TILES;
    if(is_over_max_tiles) {
        do {
            is_over_max_tiles = (app->t_settings_info.board_width * --curr_board_height) >
                                MINESWEEPER_BOARD_MAX_TILES;
        } while(is_over_max_tiles);

        app->t_settings_info.board_height = curr_board_height;

        snprintf(source, 5, "%" PRIu8, curr_board_height);
        source[4] = '\0';

        furi_string_set_strn(app->t_settings_info.height_str, source, 5);

        variable_item_set_current_value_index(
            app->t_settings_info.height_item, app->t_settings_info.board_height - 7);

        variable_item_set_current_value_text(
            app->t_settings_info.height_item,
            furi_string_get_cstr(app->t_settings_info.height_str));
    }

    snprintf(source, 5, "%" PRIu8, index + 16);
    source[4] = '\0';

    furi_string_set_strn(app->t_settings_info.width_str, source, 5);

    variable_item_set_current_value_text(
        app->t_settings_info.width_item, furi_string_get_cstr(app->t_settings_info.width_str));

    view_dispatcher_send_custom_event(
        app->view_dispatcher, MineSweeperSettingsScreenEventHeightChange);
}

static void minesweeper_scene_settings_screen_set_height(VariableItem* item) {
    char source[5];
    uint8_t index = 0;
    uint8_t curr_board_width = 16;
    bool is_over_max_tiles = false;

    furi_assert(item);

    MineSweeperApp* app = variable_item_get_context(item);
    app->t_settings_info.height_item = item;

    index = variable_item_get_current_value_index(app->t_settings_info.height_item);
    app->t_settings_info.board_height = index + 7;

    curr_board_width = app->t_settings_info.board_width;

    is_over_max_tiles = (app->t_settings_info.board_height * curr_board_width) >
                        MINESWEEPER_BOARD_MAX_TILES;
    if(is_over_max_tiles) {
        do {
            is_over_max_tiles = (app->t_settings_info.board_height * --curr_board_width) >
                                MINESWEEPER_BOARD_MAX_TILES;
        } while(is_over_max_tiles);

        app->t_settings_info.board_width = curr_board_width;

        snprintf(source, 5, "%" PRIu8, curr_board_width);
        source[4] = '\0';

        furi_string_set_strn(app->t_settings_info.width_str, source, 5);

        variable_item_set_current_value_index(
            app->t_settings_info.width_item, app->t_settings_info.board_width - 16);

        variable_item_set_current_value_text(
            app->t_settings_info.width_item, furi_string_get_cstr(app->t_settings_info.width_str));
    }

    snprintf(source, 5, "%" PRIu8, index + 7);
    source[4] = '\0';

    furi_string_set_strn(app->t_settings_info.height_str, source, 5);

    variable_item_set_current_value_text(
        app->t_settings_info.height_item, furi_string_get_cstr(app->t_settings_info.height_str));

    view_dispatcher_send_custom_event(
        app->view_dispatcher, MineSweeperSettingsScreenEventWidthChange);
}

static void minesweeper_scene_settings_screen_set_solvable(VariableItem* item) {
    furi_assert(item);

    MineSweeperApp* app = variable_item_get_context(item);

    uint8_t index = variable_item_get_current_value_index(app->t_settings_info.solvable_item);

    app->t_settings_info.ensure_solvable_board = (index == 1) ? true : false;

    variable_item_set_current_value_text(item, settings_screen_verifier_text[index]);

    view_dispatcher_send_custom_event(
        app->view_dispatcher, MineSweeperSettingsScreenEventSolvableChange);
}

static void minesweeper_scene_settings_screen_set_feedback(VariableItem* item) {
    furi_assert(item);

    MineSweeperApp* app = variable_item_get_context(item);

    uint8_t index = variable_item_get_current_value_index(item);

    app->feedback_enabled = index;

    FURI_LOG_I(TAG, "FEEDBACK CALLBACK INDEX %d", app->feedback_enabled);

    variable_item_set_current_value_text(item, ((index) ? "Enabled" : "Disabled"));

    view_dispatcher_send_custom_event(
        app->view_dispatcher, MineSweeperSettingsScreenEventFeedbackChange);
}

static void minesweeper_scene_settings_screen_set_info(VariableItem* item) {
    furi_assert(item);

    MineSweeperApp* app = variable_item_get_context(item);

    view_dispatcher_send_custom_event(
        app->view_dispatcher, MineSweeperSettingsScreenEventInfoChange);
}

void minesweeper_scene_settings_screen_on_enter(void* context) {
    furi_assert(context);

    MineSweeperApp* app = (MineSweeperApp*)context;
    VariableItemList* va = app->settings_screen;
    VariableItem* item;

    // If we are accessing the scene and have not changed the settings
    if(!app->is_settings_changed) {
        // Set temp setting buffer to current state
        app->t_settings_info = app->settings_info;
    }

    // Set Difficulty Item
    item = variable_item_list_add(
        va,
        "Difficulty",
        MineSweeperSettingsScreenDifficultyTypeNum,
        minesweeper_scene_settings_screen_set_difficulty,
        app);

    app->t_settings_info.difficulty_item = item;

    variable_item_set_current_value_index(item, app->t_settings_info.difficulty);

    variable_item_set_current_value_text(
        item, settings_screen_difficulty_text[app->t_settings_info.difficulty]);

    // Set Width Item
    item = variable_item_list_add(
        va, "Board Width", 33 - 16, minesweeper_scene_settings_screen_set_width, app);

    app->t_settings_info.width_item = item;

    variable_item_set_current_value_index(item, app->t_settings_info.board_width - 16);

    char source[5];
    snprintf(source, 5, "%" PRIu8, app->t_settings_info.board_width);
    source[4] = '\0';
    furi_string_set_strn(app->t_settings_info.width_str, source, 5);

    variable_item_set_current_value_text(
        item, furi_string_get_cstr(app->t_settings_info.width_str));

    // Set Height Item
    item = variable_item_list_add(
        va, "Board Height", 33 - 7, minesweeper_scene_settings_screen_set_height, app);

    app->t_settings_info.height_item = item;

    variable_item_set_current_value_index(item, app->t_settings_info.board_height - 7);

    snprintf(source, 5, "%" PRIu8, app->t_settings_info.board_height);
    source[4] = '\0';
    furi_string_set_strn(app->t_settings_info.height_str, source, 5);

    variable_item_set_current_value_text(
        item, furi_string_get_cstr(app->t_settings_info.height_str));

    // Set solvable item
    item = variable_item_list_add(
        va, "Ensure Solvable", 2, minesweeper_scene_settings_screen_set_solvable, app);

    app->t_settings_info.solvable_item = item;

    uint8_t idx = (app->t_settings_info.ensure_solvable_board) ? 1 : 0;

    variable_item_set_current_value_index(item, idx);

    variable_item_set_current_value_text(item, settings_screen_verifier_text[idx]);

    variable_item_set_current_value_text(item, settings_screen_verifier_text[idx]);

    // Set sound feedback item
    item = variable_item_list_add(
        va, "Feedback", 2, minesweeper_scene_settings_screen_set_feedback, app);

    variable_item_set_current_value_index(item, app->feedback_enabled);

    variable_item_set_current_value_text(item, ((app->feedback_enabled) ? "Enabled" : "Disabled"));

    // Set info item
    item = variable_item_list_add(
        va, "Right For Info", 2, minesweeper_scene_settings_screen_set_info, app);

    variable_item_set_current_value_index(item, 0);

    variable_item_set_current_value_text(item, "-------");

    view_dispatcher_switch_to_view(app->view_dispatcher, MineSweeperSettingsView);
}

bool minesweeper_scene_settings_screen_on_event(void* context, SceneManagerEvent event) {
    furi_assert(context);

    MineSweeperApp* app = context;
    bool consumed = false;

    if(event.type == SceneManagerEventTypeCustom) {
        app->is_settings_changed =
            (app->settings_info.board_width != app->t_settings_info.board_width ||
             app->settings_info.board_height != app->t_settings_info.board_height ||
             app->settings_info.difficulty != app->t_settings_info.difficulty ||
             app->settings_info.ensure_solvable_board !=
                 app->t_settings_info.ensure_solvable_board);

        switch(event.event) {
        case MineSweeperSettingsScreenEventDifficultyChange:

            break;

        case MineSweeperSettingsScreenEventWidthChange:

            break;

        case MineSweeperSettingsScreenEventHeightChange:

            break;

        case MineSweeperSettingsScreenEventSolvableChange:

            break;

        case MineSweeperSettingsScreenEventInfoChange:

        case MineSweeperSettingsScreenEventFeedbackChange:
            // If only the feedback option is changed we can just save without restarting
            mine_sweeper_save_settings(app);
            break;
        default:
            break;
        };
        consumed = true;

    } else if(event.type == SceneManagerEventTypeBack) {
        if(app->is_settings_changed) {
            // If there are changes in the width, height, or difficulty go to confirmation screen for restart

            scene_manager_next_scene(app->scene_manager, MineSweeperSceneConfirmationScreen);
        } else {
            // Otherwise just go back

            memset(&app->t_settings_info, 0, sizeof(app->t_settings_info));

            if(!scene_manager_search_and_switch_to_previous_scene(
                   app->scene_manager, MineSweeperSceneMenuScreen)) {
                scene_manager_stop(app->scene_manager);
                view_dispatcher_stop(app->view_dispatcher);
            }
        }

        consumed = true;
    }

    return consumed;
}

void minesweeper_scene_settings_screen_on_exit(void* context) {
    furi_assert(context);
    MineSweeperApp* app = (MineSweeperApp*)context;
    VariableItemList* va = app->settings_screen;

    variable_item_list_reset(va);
}
