#include "keybinds.h"
#include <gdk/gdkkeysyms.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

/* Default keybind table */
static const Keybind default_keybinds[KEYBIND_COUNT] = {
    { KEYBIND_PLAY_PAUSE,      "Play/Pause",       GDK_space,     0 },
    { KEYBIND_STOP,            "Stop",              GDK_s,         0 },
    { KEYBIND_FULLSCREEN,      "Fullscreen",        GDK_f,         0 },
    { KEYBIND_EXIT_FULLSCREEN, "Exit Fullscreen",   GDK_Escape,    0 },
    { KEYBIND_SEEK_FORWARD,    "Seek Forward",      GDK_Right,     0 },
    { KEYBIND_SEEK_BACKWARD,   "Seek Backward",     GDK_Left,      0 },
    { KEYBIND_VOLUME_UP,       "Volume Up",         GDK_Up,        0 },
    { KEYBIND_VOLUME_DOWN,     "Volume Down",       GDK_Down,      0 },
    { KEYBIND_MUTE,            "Mute",              GDK_m,         0 },
    { KEYBIND_PREV_CHAPTER,    "Previous Chapter",  GDK_Page_Up,   0 },
    { KEYBIND_NEXT_CHAPTER,    "Next Chapter",      GDK_Page_Down, 0 },
    { KEYBIND_FRAME_STEP,      "Frame Step",        GDK_period,    0 },
    { KEYBIND_OPEN_FILE,       "Open File",         GDK_o,         GDK_CONTROL_MASK },
    { KEYBIND_OPEN_URL,        "Open URL",          GDK_l,         GDK_CONTROL_MASK },
    { KEYBIND_GOTO_TIME,       "Go to Time",        GDK_g,         GDK_CONTROL_MASK },
    { KEYBIND_SCREENSHOT,      "Screenshot",        GDK_s,         GDK_CONTROL_MASK | GDK_SHIFT_MASK },
    { KEYBIND_TOGGLE_PLAYLIST, "Toggle Playlist",   GDK_p,         GDK_CONTROL_MASK },
    { KEYBIND_QUIT,            "Quit",              GDK_q,         GDK_CONTROL_MASK },
};

KeybindManager* keybind_manager_new(void)
{
    KeybindManager *km = g_new0(KeybindManager, 1);
    keybind_manager_reset_defaults(km);
    return km;
}

void keybind_manager_free(KeybindManager *km)
{
    if (km) g_free(km);
}

void keybind_manager_reset_defaults(KeybindManager *km)
{
    if (!km) return;
    memcpy(km->binds, default_keybinds, sizeof(default_keybinds));
}

void keybind_manager_load(KeybindManager *km, GKeyFile *keyfile)
{
    if (!km || !keyfile) return;
    
    /* Start from defaults, then override with saved values */
    keybind_manager_reset_defaults(km);
    
    if (!g_key_file_has_group(keyfile, "Keybinds")) return;
    
    for (int i = 0; i < KEYBIND_COUNT; i++) {
        const char *action_name = km->binds[i].label;
        GError *error = NULL;
        
        /* Build key names like "Play/Pause_key" and "Play/Pause_mods" */
        char key_name[128];
        char mod_name[128];
        snprintf(key_name, sizeof(key_name), "%s_key", action_name);
        snprintf(mod_name, sizeof(mod_name), "%s_mods", action_name);
        
        char *keyval_str = g_key_file_get_string(keyfile, "Keybinds", key_name, &error);
        if (keyval_str && !error) {
            guint kv = gdk_keyval_from_name(keyval_str);
            if (kv != 0xffffff) { /* GDK_KEY_VoidSymbol */
                km->binds[i].keyval = kv;
            }
            g_free(keyval_str);
        }
        if (error) { g_error_free(error); error = NULL; }
        
        int mods_val = g_key_file_get_integer(keyfile, "Keybinds", mod_name, &error);
        if (!error) {
            km->binds[i].mods = (GdkModifierType)mods_val;
        }
        if (error) { g_error_free(error); error = NULL; }
    }
}

void keybind_manager_save(KeybindManager *km, GKeyFile *keyfile)
{
    if (!km || !keyfile) return;
    
    for (int i = 0; i < KEYBIND_COUNT; i++) {
        const char *action_name = km->binds[i].label;
        char key_name[128];
        char mod_name[128];
        snprintf(key_name, sizeof(key_name), "%s_key", action_name);
        snprintf(mod_name, sizeof(mod_name), "%s_mods", action_name);
        
        const char *keyval_str = gdk_keyval_name(km->binds[i].keyval);
        if (keyval_str) {
            g_key_file_set_string(keyfile, "Keybinds", key_name, keyval_str);
        }
        g_key_file_set_integer(keyfile, "Keybinds", mod_name, (int)km->binds[i].mods);
    }
}

void keybind_manager_set_keybind(KeybindManager *km, KeybindAction action, guint keyval, GdkModifierType mods)
{
    if (!km || action < 0 || action >= KEYBIND_COUNT) return;
    km->binds[action].keyval = keyval;
    km->binds[action].mods = mods;
}

Keybind* keybind_manager_get(KeybindManager *km, KeybindAction action)
{
    if (!km || action < 0 || action >= KEYBIND_COUNT) return NULL;
    return &km->binds[action];
}

KeybindAction keybind_manager_find_action(KeybindManager *km, guint keyval, GdkModifierType mods)
{
    if (!km) return KEYBIND_COUNT;
    
    /* Mask out irrelevant modifier bits (lock keys, etc.) */
    GdkModifierType relevant = GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK;
    GdkModifierType clean_mods = mods & relevant;
    
    for (int i = 0; i < KEYBIND_COUNT; i++) {
        if (km->binds[i].keyval == keyval && km->binds[i].mods == clean_mods) {
            return (KeybindAction)i;
        }
    }
    return KEYBIND_COUNT; /* not found */
}

char* keybind_get_display_string(guint keyval, GdkModifierType mods)
{
    GString *str = g_string_new(NULL);
    
    if (mods & GDK_CONTROL_MASK) g_string_append(str, "Ctrl+");
    if (mods & GDK_SHIFT_MASK)   g_string_append(str, "Shift+");
    if (mods & GDK_MOD1_MASK)    g_string_append(str, "Alt+");
    
    const char *name = gdk_keyval_name(keyval);
    if (name) {
        /* Capitalize first letter for display */
        if (strlen(name) == 1 && name[0] >= 'a' && name[0] <= 'z') {
            g_string_append_c(str, name[0] - 32);
        } else {
            g_string_append(str, name);
        }
    } else {
        g_string_append(str, "???");
    }
    
    return g_string_free(str, FALSE);
}
