#include "controls.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>

struct Controls {
    Player *player;
    Preferences *prefs;
    
    /* Main container */
    GtkWidget *root; /* GtkEventBox for background/windowing */
    GtkWidget *hbox; /* Actual layout */
    
    /* Playback buttons */
    GtkWidget *btn_prev;
    GtkWidget *btn_play_pause;
    GtkWidget *btn_stop;
    GtkWidget *btn_next;
    
    /* Seek */
    GtkWidget *seek_scale;
    GtkWidget *time_label;
    gboolean seeking;
    double duration;
    
    /* Volume */
    GtkWidget *volume_scale;
    GtkWidget *btn_mute;
    gboolean muted;
    
    /* Fullscreen */
    GtkWidget *btn_fullscreen;
    ControlsFullscreenCallback fullscreen_callback;
    gpointer fullscreen_callback_data;
    
    /* Play/Pause Callback */
    ControlsPlayPauseCallback play_pause_callback;
    gpointer play_pause_callback_data;
    
    gboolean is_fullscreen;
    
    /* Icons (stock icons) */
    GtkWidget *play_image;
    GtkWidget *pause_image;
    
    /* Chapters for snapping/markers */
    double *chapter_times;
    int chapter_count;
};

/* Forward declarations */
static void on_play_pause_clicked(GtkButton *button, gpointer data);
static void on_stop_clicked(GtkButton *button, gpointer data);
static void on_prev_clicked(GtkButton *button, gpointer data);
static double snap_to_chapter(Controls *controls, double val);
static void on_next_clicked(GtkButton *button, gpointer data);
static void on_mute_clicked(GtkButton *button, gpointer data);
static void on_fullscreen_clicked(GtkButton *button, gpointer data);
static gboolean on_seek_change_value(GtkRange *range, GtkScrollType scroll, gdouble value, gpointer data);

#define SNAP_THRESHOLD 5.0 /* seconds */
static gboolean on_seek_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data);
static gboolean on_seek_button_release(GtkWidget *widget, GdkEventButton *event, gpointer data);
static gboolean on_seek_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer data);
static void on_volume_changed(GtkRange *range, gpointer data);

static void format_time(double seconds, char *buffer, size_t size)
{
    int total_secs = (int)seconds;
    int hours = total_secs / 3600;
    int mins = (total_secs % 3600) / 60;
    int secs = total_secs % 60;
    
    if (hours > 0) {
        snprintf(buffer, size, "%d:%02d:%02d", hours, mins, secs);
    } else {
        snprintf(buffer, size, "%d:%02d", mins, secs);
    }
}

Controls* controls_new(Player *player, Preferences *prefs)
{
    Controls *controls = g_new0(Controls, 1);
    controls->player = player;
    controls->prefs = prefs;
    controls->seeking = FALSE;
    controls->duration = 0.0;
    controls->muted = FALSE;
    controls->is_fullscreen = FALSE;
    
    /* Main container */
    controls->root = gtk_event_box_new();
    
    /* Main horizontal box */
    controls->hbox = gtk_hbox_new(FALSE, 5);
    gtk_container_set_border_width(GTK_CONTAINER(controls->hbox), 5);
    /* Set a fixed height to prevent layout shift when markers appear at the bottom */
    gtk_widget_set_size_request(controls->hbox, -1, 50);
    gtk_container_add(GTK_CONTAINER(controls->root), controls->hbox);
    
    /* Left side buttons container, wrapped in alignment to prevent vertical stretch */
    GtkWidget *left_align = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
    GtkWidget *left_box = gtk_hbox_new(FALSE, 5);
    gtk_container_add(GTK_CONTAINER(left_align), left_box);
    gtk_box_pack_start(GTK_BOX(controls->hbox), left_align, FALSE, FALSE, 0);

    /* Previous button */
    controls->btn_prev = gtk_button_new();
    gtk_button_set_image(GTK_BUTTON(controls->btn_prev), 
                         gtk_image_new_from_stock(GTK_STOCK_MEDIA_PREVIOUS, GTK_ICON_SIZE_BUTTON));
    gtk_widget_set_size_request(controls->btn_prev, 36, 36);
    gtk_widget_set_tooltip_text(controls->btn_prev, "Previous");
    g_signal_connect(controls->btn_prev, "clicked", G_CALLBACK(on_prev_clicked), controls);
    gtk_box_pack_start(GTK_BOX(left_box), controls->btn_prev, FALSE, FALSE, 0);
    
    /* Play/Pause button */
    controls->btn_play_pause = gtk_button_new();
    controls->play_image = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON);
    controls->pause_image = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_BUTTON);
    g_object_ref(controls->play_image);
    g_object_ref(controls->pause_image);
    gtk_button_set_image(GTK_BUTTON(controls->btn_play_pause), controls->play_image);
    gtk_widget_set_size_request(controls->btn_play_pause, 36, 36);
    gtk_widget_set_tooltip_text(controls->btn_play_pause, "Play/Pause");
    g_signal_connect(controls->btn_play_pause, "clicked", G_CALLBACK(on_play_pause_clicked), controls);
    gtk_box_pack_start(GTK_BOX(left_box), controls->btn_play_pause, FALSE, FALSE, 0);
    
    /* Stop button */
    controls->btn_stop = gtk_button_new();
    gtk_button_set_image(GTK_BUTTON(controls->btn_stop),
                         gtk_image_new_from_stock(GTK_STOCK_MEDIA_STOP, GTK_ICON_SIZE_BUTTON));
    gtk_widget_set_size_request(controls->btn_stop, 36, 36);
    gtk_widget_set_tooltip_text(controls->btn_stop, "Stop");
    g_signal_connect(controls->btn_stop, "clicked", G_CALLBACK(on_stop_clicked), controls);
    gtk_box_pack_start(GTK_BOX(left_box), controls->btn_stop, FALSE, FALSE, 0);
    
    /* Next button */
    controls->btn_next = gtk_button_new();
    gtk_button_set_image(GTK_BUTTON(controls->btn_next),
                         gtk_image_new_from_stock(GTK_STOCK_MEDIA_NEXT, GTK_ICON_SIZE_BUTTON));
    gtk_widget_set_size_request(controls->btn_next, 36, 36);
    gtk_widget_set_tooltip_text(controls->btn_next, "Next");
    g_signal_connect(controls->btn_next, "clicked", G_CALLBACK(on_next_clicked), controls);
    gtk_box_pack_start(GTK_BOX(left_box), controls->btn_next, FALSE, FALSE, 0);
    
    /* Separator (inside the stretchable area) */
    gtk_box_pack_start(GTK_BOX(controls->hbox), gtk_vseparator_new(), FALSE, FALSE, 5);
    
    /* Seek slider */
    controls->seek_scale = gtk_hscale_new_with_range(0, 100, 1);
    gtk_scale_set_draw_value(GTK_SCALE(controls->seek_scale), FALSE);
    gtk_range_set_value(GTK_RANGE(controls->seek_scale), 0);
    gtk_widget_set_size_request(controls->seek_scale, 200, -1);
    g_signal_connect(controls->seek_scale, "change-value", G_CALLBACK(on_seek_change_value), controls);
    g_signal_connect(controls->seek_scale, "button-press-event", G_CALLBACK(on_seek_button_press), controls);
    g_signal_connect(controls->seek_scale, "button-release-event", G_CALLBACK(on_seek_button_release), controls);
    g_signal_connect(controls->seek_scale, "motion-notify-event", G_CALLBACK(on_seek_motion_notify), controls);
    gtk_box_pack_start(GTK_BOX(controls->hbox), controls->seek_scale, TRUE, TRUE, 0);
    
    /* Right side buttons container, wrapped in alignment to prevent vertical stretch */
    GtkWidget *right_align = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
    GtkWidget *right_box = gtk_hbox_new(FALSE, 5);
    gtk_container_add(GTK_CONTAINER(right_align), right_box);
    gtk_box_pack_start(GTK_BOX(controls->hbox), right_align, FALSE, FALSE, 0);

    /* Time label */
    controls->time_label = gtk_label_new("0:00 / 0:00");
    gtk_misc_set_alignment(GTK_MISC(controls->time_label), 0.5, 0.5);
    /* gtk_widget_set_size_request(controls->time_label, 85, -1); */
    gtk_box_pack_start(GTK_BOX(right_box), controls->time_label, FALSE, FALSE, 2);
    
    /* Separator */
    gtk_box_pack_start(GTK_BOX(right_box), gtk_vseparator_new(), FALSE, FALSE, 2);
    
    /* Volume button (mute toggle) */
    controls->btn_mute = gtk_button_new();
    GtkWidget *mute_img = gtk_image_new_from_icon_name("audio-volume-high", GTK_ICON_SIZE_BUTTON);
    gtk_button_set_image(GTK_BUTTON(controls->btn_mute), mute_img);
    gtk_widget_set_size_request(controls->btn_mute, 36, 36);
    gtk_widget_set_tooltip_text(controls->btn_mute, "Mute/Unmute");
    g_signal_connect(controls->btn_mute, "clicked", G_CALLBACK(on_mute_clicked), controls);
    gtk_box_pack_start(GTK_BOX(right_box), controls->btn_mute, FALSE, FALSE, 0);
    
    /* Volume slider */
    double max_vol = (prefs && prefs->enable_volume_boost) ? 150.0 : 100.0;
    controls->volume_scale = gtk_hscale_new_with_range(0, max_vol, 1);
    gtk_scale_set_draw_value(GTK_SCALE(controls->volume_scale), FALSE);
#if GTK_CHECK_VERSION(2,16,0)
    if (prefs && prefs->enable_volume_boost) {
        gtk_scale_add_mark(GTK_SCALE(controls->volume_scale), 100, GTK_POS_BOTTOM, NULL);
    }
#endif
    gtk_range_set_value(GTK_RANGE(controls->volume_scale), 100);
    gtk_widget_set_size_request(controls->volume_scale, 80, -1);
    gtk_widget_set_tooltip_text(controls->volume_scale, "Volume");
    g_signal_connect(controls->volume_scale, "value-changed", G_CALLBACK(on_volume_changed), controls);
    gtk_box_pack_start(GTK_BOX(right_box), controls->volume_scale, FALSE, FALSE, 0);
    
    /* Separator */
    gtk_box_pack_start(GTK_BOX(right_box), gtk_vseparator_new(), FALSE, FALSE, 5);
    
    /* Fullscreen button */
    controls->btn_fullscreen = gtk_button_new();
    gtk_button_set_image(GTK_BUTTON(controls->btn_fullscreen),
                         gtk_image_new_from_stock(GTK_STOCK_FULLSCREEN, GTK_ICON_SIZE_BUTTON));
    gtk_widget_set_size_request(controls->btn_fullscreen, 36, 36);
    gtk_widget_set_tooltip_text(controls->btn_fullscreen, "Fullscreen");
    g_signal_connect(controls->btn_fullscreen, "clicked", G_CALLBACK(on_fullscreen_clicked), controls);
    gtk_box_pack_start(GTK_BOX(right_box), controls->btn_fullscreen, FALSE, FALSE, 0);
    
    gtk_widget_show_all(controls->root);
    
    return controls;
}

void controls_destroy(Controls *controls)
{
    if (!controls) return;
    
    if (controls->play_image) g_object_unref(controls->play_image);
    if (controls->pause_image) g_object_unref(controls->pause_image);
    if (controls->chapter_times) g_free(controls->chapter_times);
    g_free(controls);
}

GtkWidget* controls_get_widget(Controls *controls)
{
    if (!controls) return NULL;
    return controls->root;
}

void controls_update_position(Controls *controls, double position)
{
    if (!controls || controls->seeking) return;
    
    /* Update seek slider */
    if (controls->duration > 0) {
        double percent = (position / controls->duration) * 100.0;
        gtk_range_set_value(GTK_RANGE(controls->seek_scale), percent);
    }
    
    /* Update time label */
    char pos_str[32], dur_str[32], label_str[72];
    format_time(position, pos_str, sizeof(pos_str));
    format_time(controls->duration, dur_str, sizeof(dur_str));
    snprintf(label_str, sizeof(label_str), "%s / %s", pos_str, dur_str);
    gtk_label_set_text(GTK_LABEL(controls->time_label), label_str);
}

void controls_update_duration(Controls *controls, double duration)
{
    if (!controls) return;
    controls->duration = duration;
    
    /* Update slider range (still use 0-100 percent) */
    gtk_range_set_range(GTK_RANGE(controls->seek_scale), 0, 100);
    
    /* Refresh markers if we have them */
    if (controls->chapter_count > 0 && controls->chapter_times) {
        controls_set_chapters(controls, controls->chapter_count, controls->chapter_times);
    }
}

void controls_update_pause_state(Controls *controls, gboolean paused)
{
    if (!controls) return;
    
    GtkWidget *image = paused ? controls->play_image : controls->pause_image;
    gtk_button_set_image(GTK_BUTTON(controls->btn_play_pause), image);
}

void controls_update_volume(Controls *controls, double volume)
{
    if (!controls) return;
    
    /* Block signal to avoid feedback loop */
    g_signal_handlers_block_by_func(controls->volume_scale, on_volume_changed, controls);
    gtk_range_set_value(GTK_RANGE(controls->volume_scale), volume);
    g_signal_handlers_unblock_by_func(controls->volume_scale, on_volume_changed, controls);
}

void controls_update_mute_state(Controls *controls, gboolean muted)
{
    if (!controls) return;
    
    controls->muted = muted;
    const char *icon_name = muted ? "audio-volume-muted" : "audio-volume-high";
    gtk_button_set_image(GTK_BUTTON(controls->btn_mute), 
                         gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_BUTTON));
}

void controls_update_title(Controls *controls, const char *title)
{
    /* This might be used for a title label in controls, currently unused */
    (void)controls;
    (void)title;
}

void controls_reset(Controls *controls)
{
    if (!controls) return;
    controls->duration = 0;
    gtk_range_set_value(GTK_RANGE(controls->seek_scale), 0);
    gtk_label_set_text(GTK_LABEL(controls->time_label), "0:00 / 0:00");
    
    if (controls->chapter_times) {
        g_free(controls->chapter_times);
        controls->chapter_times = NULL;
    }
    controls->chapter_count = 0;
    
    /* Clear markers */
#if GTK_CHECK_VERSION(2,16,0)
    gtk_scale_clear_marks(GTK_SCALE(controls->seek_scale));
#endif
    
    /* Show play icon */
    gtk_button_set_image(GTK_BUTTON(controls->btn_play_pause), controls->play_image);
}

void controls_set_chapters(Controls *controls, int count, double *times)
{
    if (!controls) return;
    
    if (controls->chapter_times) {
        g_free(controls->chapter_times);
        controls->chapter_times = NULL;
    }
    
    /* If the preference is visually off, we disable counting and marks entirely */
    if (controls->prefs && !controls->prefs->enable_chapters) {
        controls->chapter_count = 0;
#if GTK_CHECK_VERSION(2,16,0)
        gtk_scale_clear_marks(GTK_SCALE(controls->seek_scale));
#endif
        return;
    }
    
    controls->chapter_count = count;
    if (count > 0 && times) {
        controls->chapter_times = g_new0(double, count);
        memcpy(controls->chapter_times, times, sizeof(double) * count);
    } else {
        controls->chapter_times = NULL;
    }
    
    /* Add markers to scale if supported */
#if GTK_CHECK_VERSION(2,16,0)
    gtk_scale_clear_marks(GTK_SCALE(controls->seek_scale));
    if (controls->duration > 0 && count > 0 && times) {
        for (int i = 0; i < count; i++) {
            double val = (times[i] / controls->duration) * 100.0;
            gtk_scale_add_mark(GTK_SCALE(controls->seek_scale), val, GTK_POS_BOTTOM, NULL);
        }
    }
#endif
}

void controls_set_seeking(Controls *controls, gboolean seeking)
{
    if (!controls) return;
    controls->seeking = seeking;
}

gboolean controls_is_seeking(Controls *controls)
{
    if (!controls) return FALSE;
    return controls->seeking;
}

void controls_set_fullscreen_callback(Controls *controls,
                                      ControlsFullscreenCallback callback,
                                      gpointer user_data)
{
    if (!controls) return;
    controls->fullscreen_callback = callback;
    controls->fullscreen_callback_data = user_data;
}

void controls_set_play_pause_callback(Controls *controls,
                                      ControlsPlayPauseCallback callback,
                                      gpointer user_data)
{
    if (!controls) return;
    controls->play_pause_callback = callback;
    controls->play_pause_callback_data = user_data;
}

/* Signal handlers */

static void on_play_pause_clicked(GtkButton *button, gpointer data)
{
    (void)button;
    Controls *controls = (Controls *)data;
    
    if (controls->play_pause_callback) {
        controls->play_pause_callback(controls->play_pause_callback_data);
    } else {
        player_toggle_pause(controls->player);
    }
}

static void on_stop_clicked(GtkButton *button, gpointer data)
{
    (void)button;
    Controls *controls = (Controls *)data;
    player_stop(controls->player);
}

static void on_prev_clicked(GtkButton *button, gpointer data)
{
    (void)button;
    Controls *controls = (Controls *)data;
    player_playlist_prev(controls->player);
}

static void on_next_clicked(GtkButton *button, gpointer data)
{
    (void)button;
    Controls *controls = (Controls *)data;
    player_playlist_next(controls->player);
}

static void on_mute_clicked(GtkButton *button, gpointer data)
{
    (void)button;
    Controls *controls = (Controls *)data;
    player_set_muted(controls->player, !controls->muted);
}

static void on_fullscreen_clicked(GtkButton *button, gpointer data)
{
    (void)button;
    Controls *controls = (Controls *)data;
    
    controls->is_fullscreen = !controls->is_fullscreen;
    
    if (controls->fullscreen_callback) {
        controls->fullscreen_callback(controls->is_fullscreen, 
                                      controls->fullscreen_callback_data);
    }
}

static gboolean on_seek_change_value(GtkRange *range, GtkScrollType scroll, gdouble value, gpointer data)
{
    (void)range;
    (void)scroll;
    Controls *controls = (Controls *)data;
    
    if (controls->duration > 0) {
        double position = (value / 100.0) * controls->duration;
        player_seek_absolute(controls->player, position);
    }
    
    return FALSE;
}

static gboolean on_seek_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
    Controls *controls = (Controls *)data;
    gtk_widget_grab_focus(widget);
    controls->seeking = TRUE;
    
    if (event->button == 1) {
        if (controls->prefs && controls->prefs->seekbar_direct_jump) {
            /* Left click jump-to-position */
            GtkRange *range = GTK_RANGE(widget);
            GtkAdjustment *adj = gtk_range_get_adjustment(range);
            
            /* Calculate relative position (0.0 to 1.0) using widget-relative coordinates */
            gint x;
            gtk_widget_get_pointer(widget, &x, NULL);
            
            double relative = x / (double)widget->allocation.width;
            if (relative < 0) relative = 0;
            if (relative > 1) relative = 1;
            
            double new_val = adj->lower + relative * (adj->upper - adj->lower);
            
            /* Snap to chapter if close */
            new_val = snap_to_chapter(controls, new_val);
            
            gtk_range_set_value(range, new_val);
            
            /* Perform seek immediately */
            if (controls->duration > 0) {
                double position = (new_val / 100.0) * controls->duration;
                player_seek_absolute(controls->player, position);
            }
            
            /* Signal handled to prevent GTK from doing its own thing (like jumping by page) */
            return TRUE;
        }
    }
    
    return FALSE;
}

static gboolean on_seek_button_release(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
    (void)widget;
    (void)event;
    Controls *controls = (Controls *)data;
    controls->seeking = FALSE;
    return FALSE;
}

static double snap_to_chapter(Controls *controls, double val)
{
    /* Get seekbar width to calculate pixel-based threshold */
    int width = controls->seek_scale->allocation.width;
    if (width <= 0) return val;
    
    double snap_pixels = 3.0;
    double snap_percent = (snap_pixels / (double)width) * 100.0;
    
    for (int i = 0; i < controls->chapter_count; i++) {
        if (controls->duration <= 0) continue;
        double chapter_percent = (controls->chapter_times[i] / controls->duration) * 100.0;
        if (fabs(val - chapter_percent) < snap_percent) {
            return chapter_percent;
        }
    }
    
    return val;
}

static gboolean on_seek_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer data)
{
    Controls *controls = (Controls *)data;
    
    if (controls->seeking && (event->state & GDK_BUTTON1_MASK)) {
        GtkRange *range = GTK_RANGE(widget);
        GtkAdjustment *adj = gtk_range_get_adjustment(range);
        
        gint x;
        gtk_widget_get_pointer(widget, &x, NULL);
        
        double relative = x / (double)widget->allocation.width;
        if (relative < 0) relative = 0;
        if (relative > 1) relative = 1;
        
        double new_val = adj->lower + relative * (adj->upper - adj->lower);
        
        /* Snap to chapter if close */
        new_val = snap_to_chapter(controls, new_val);
        
        gtk_range_set_value(range, new_val);
        
        if (controls->duration > 0) {
            double position = (new_val / 100.0) * controls->duration;
            player_seek_absolute(controls->player, position);
        }
        return TRUE;
    }
    
    return FALSE;
}

static void on_volume_changed(GtkRange *range, gpointer data)
{
    Controls *controls = (Controls *)data;
    double volume = gtk_range_get_value(range);
    
    /* Magnetic snapping to 100% only if boost is on */
    if (controls->prefs && controls->prefs->enable_volume_boost) {
        if (fabs(volume - 100.0) < 4.0 && volume != 100.0) {
            gtk_range_set_value(range, 100.0);
            return; /* Let recursive call handle backend update */
        }
    }
    
    player_set_volume(controls->player, volume);
}

void controls_update_volume_boost(Controls *controls, gboolean enable)
{
    if (!controls || !controls->volume_scale) return;
    
    double current = gtk_range_get_value(GTK_RANGE(controls->volume_scale));
    gtk_range_set_range(GTK_RANGE(controls->volume_scale), 0, enable ? 150.0 : 100.0);
    
#if GTK_CHECK_VERSION(2,16,0)
    gtk_scale_clear_marks(GTK_SCALE(controls->volume_scale));
    if (enable) {
        gtk_scale_add_mark(GTK_SCALE(controls->volume_scale), 100, GTK_POS_BOTTOM, NULL);
    }
#endif
    
    if (!enable && current > 100.0) {
        gtk_range_set_value(GTK_RANGE(controls->volume_scale), 100.0);
    }
}
