#include "libublsettingsui-gtk3.h"

#define sha256_encrypt_command(target) yon_char_unite("echo -n \"",target,"\" | sha256sum | cut -f 1 -d ' '",NULL)
#define sha512_encrypt_command(target) yon_char_unite("echo -n \"",target,"\" | sha512sum | cut -f 1 -d ' '",NULL)

yon_password_window *yon_password_window_new();
gboolean on_password_focus_out_event(GtkWidget *self, GdkEvent *, yon_password_window *window);

gboolean on_password_focus_event(GtkWidget *self, GdkEvent *, yon_password_window *window){
	gtk_popover_set_relative_to(GTK_POPOVER(window->PasswordTooltipPopover),self);
	gtk_popover_set_position(GTK_POPOVER(window->PasswordTooltipPopover),GTK_POS_RIGHT);
	g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window);
	g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window);
	gtk_popover_popup(GTK_POPOVER(window->PasswordTooltipPopover));
	gtk_widget_grab_focus(self);
	g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window);
	g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window);
	return GDK_EVENT_PROPAGATE;
} 

gboolean on_password_focus_out_event(GtkWidget *self, GdkEvent *, yon_password_window *window){
	gtk_popover_set_relative_to(GTK_POPOVER(window->PasswordTooltipPopover),self);
	gtk_popover_set_position(GTK_POPOVER(window->PasswordTooltipPopover),GTK_POS_RIGHT);
	gtk_popover_popdown(GTK_POPOVER(window->PasswordTooltipPopover));
	return GDK_EVENT_PROPAGATE;
}
gboolean on_password_tooltip_event(GtkWidget *self, GdkEvent *, yon_password_window *window){
	gtk_popover_set_relative_to(GTK_POPOVER(window->PasswordTooltipPopover),self);
	gtk_popover_set_position(GTK_POPOVER(window->PasswordTooltipPopover),GTK_POS_RIGHT);
	g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window);
	g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window);
	gtk_popover_popup(GTK_POPOVER(window->PasswordTooltipPopover));
	g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window);
	g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window);
	return GDK_EVENT_PROPAGATE;
}

gboolean on_password_tooltip_out_event(GtkWidget *self, GdkEvent *, yon_password_window *window){
	if (gtk_widget_has_focus(window->PasswordEntry)) return GDK_EVENT_PROPAGATE;
	gtk_popover_set_relative_to(GTK_POPOVER(window->PasswordTooltipPopover),self);
	gtk_popover_set_position(GTK_POPOVER(window->PasswordTooltipPopover),GTK_POS_RIGHT);
	gtk_popover_popdown(GTK_POPOVER(window->PasswordTooltipPopover));
	return GDK_EVENT_PROPAGATE;
}

char *yon_password_unencrypted_password_get(yon_password_window *window){
    const char *password = gtk_entry_get_text(GTK_ENTRY(window->PasswordEntry));
    const char *password_repeat = gtk_entry_get_text(GTK_ENTRY(window->RepeatPasswordEntry));

    if (window->strength_func){
        double password_strength = ((double(*)(yon_password_window *,const char*))window->strength_func)(window,password);
        if (password_strength<0.3){
            yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_WEAK_PASSWORD_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE);
            return NULL;
        }
    } else if (strpbrk(password,"!@#%^&*\'")){
        yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_PASSWORD_RESTRICTED_SYMBOL_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE);
        yon_ubl_status_highlight_incorrect(window->PasswordEntry);
        return NULL;
    }
    if (strcmp(password,password_repeat)){
        yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_PASSWORD_MISMATCH_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE);
        yon_ubl_status_highlight_incorrect(window->PasswordEntry);
        yon_ubl_status_highlight_incorrect(window->RepeatPasswordEntry);
        return NULL;
    }
    if (yon_char_is_empty(password)){
        yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_EMPTY_IMPORTANT_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE);
        yon_ubl_status_highlight_incorrect(window->PasswordEntry);
        return NULL;
    }

    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(window->NoEncriptionCheck))){
        const char *encryption = gtk_combo_box_get_active_id(GTK_COMBO_BOX(window->EncryptionCombo));
        char *final = yon_char_unite(encryption,"|",password,NULL);
        return final;
    } else {
        return yon_char_new(password);
    }
}

char *yon_password_hash_get(yon_password_window *window){
    int encription_active = gtk_combo_box_get_active(GTK_COMBO_BOX(window->EncryptionCombo));
    const char *encription = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(window->EncryptionCombo));
    const char *encription_command = gtk_combo_box_get_active_id(GTK_COMBO_BOX(window->EncryptionCombo));
    const char *hash = gtk_entry_get_text(GTK_ENTRY(window->PasswordHashEntry));
    if (!yon_char_is_empty(hash)){
        // if (!yon_char_is_empty(window->old_password)&&strcmp(hash,window->old_password)){
            switch(encription_active){
                case 1:{
                    if (strlen(hash)!=128){
                yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_INCORRECT_HASH_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE);
                yon_ubl_status_highlight_incorrect(window->PasswordHashEntry);
                return NULL;
            }
                }
                    break;
                case 2:{
                    if (strlen(hash)!=64){
                yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_INCORRECT_HASH_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE);
                yon_ubl_status_highlight_incorrect(window->PasswordHashEntry);
                return NULL;
            }
                }
                    break;
            }
        // }
        char *final = yon_char_unite(encription,"|",hash,NULL);
        return final;
    } else {
        const char *password = gtk_entry_get_text(GTK_ENTRY(window->PasswordEntry));
        const char *password_repeat = gtk_entry_get_text(GTK_ENTRY(window->RepeatPasswordEntry));
        if (window->strength_func){
            double password_strength = ((double(*)(yon_password_window *,const char*))window->strength_func)(window,password);
            if (password_strength<0.3){
                yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_WEAK_PASSWORD_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE);
                return NULL;
            }
        } else if (strpbrk(password,"!@#%^&*\'")){
            yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_PASSWORD_RESTRICTED_SYMBOL_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE);
            yon_ubl_status_highlight_incorrect(window->PasswordEntry);
            return NULL;
        }
        if (yon_char_is_empty(password_repeat)){
            yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_EMPTY_IMPORTANT_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE);
            yon_ubl_status_highlight_incorrect(window->RepeatPasswordEntry);
            return NULL;
        }
        if (strcmp(password,password_repeat)){
            yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),_PASSWORD_MISMATCH_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE);
            yon_ubl_status_highlight_incorrect(window->PasswordEntry);
            yon_ubl_status_highlight_incorrect(window->RepeatPasswordEntry);
            return NULL;
        }

        int size;
        config_str hash = yon_config_load(yon_debug_output("%s\n",encription_active==1?sha512_encrypt_command(password):sha256_encrypt_command(password)),&size);
            yon_char_remove_last_symbol(hash[0],'\n');

        char *final = hash[0];
        if (gtk_widget_get_visible(window->EncryptionCombo)){
            final = yon_char_unite(encription,"|",hash[0],NULL);
        }
        return final;
    }
    return NULL;
}

void on_password_encryption_changed(GtkComboBox *self, yon_password_window *dialog){
    int active = gtk_combo_box_get_active(self);
        gtk_widget_set_sensitive(dialog->NoEncriptionCheck,!!active);
        if (!active)
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->NoEncriptionCheck),0);
}

void yon_hash_entry_sensitiveness_update(GtkWidget *, yon_password_window *dialog){
    int hash_type_sensitive = gtk_combo_box_get_active(GTK_COMBO_BOX(dialog->EncryptionCombo));
    int encrypt_sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->NoEncriptionCheck));
    if (!encrypt_sensitive&&hash_type_sensitive) gtk_widget_set_sensitive(dialog->PasswordHashEntry,1);
    else gtk_widget_set_sensitive(dialog->PasswordHashEntry,0);
}

void yon_password_hash_list_set(yon_password_window *window, config_str hashes, config_str get_hash_commands, int size){
    gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(window->EncryptionCombo));
    gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(window->EncryptionCombo),"",_ENCRYPTION_DEFAULT_LABEL);
    if (!size){
        gtk_widget_hide(gtk_widget_get_parent(window->EncryptionCombo));
        gtk_widget_hide(window->NoEncriptionCheck);
        gtk_widget_hide(window->HashBox);
    }
    
    for (int i=0;i<size;i++){
        gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(window->EncryptionCombo),get_hash_commands[i],hashes[i]);
    }
}

void on_password_hash_sensitiveness(GtkWidget *,yon_password_window *window){
    const char *password = gtk_entry_get_text(GTK_ENTRY(window->PasswordEntry));
    const char *repeat_password = gtk_entry_get_text(GTK_ENTRY(window->RepeatPasswordEntry));
    const char *hash = gtk_entry_get_text(GTK_ENTRY(window->PasswordHashEntry));
    const char *hash_command = gtk_combo_box_get_active_id(GTK_COMBO_BOX(window->EncryptionCombo));
    if (!yon_char_is_empty(hash_command)){
        gtk_widget_set_sensitive(window->NoEncriptionCheck,1);
    } else {
        gtk_widget_set_sensitive(window->NoEncriptionCheck,0);
    }
	if (!yon_char_is_empty(password)||!yon_char_is_empty(repeat_password)){
		gtk_widget_set_sensitive(window->HashBox,0);
		gtk_widget_set_sensitive(window->PasswordBox,1);
    } else if (yon_char_is_empty(password)&&yon_char_is_empty(repeat_password)&&
                gtk_combo_box_get_active(GTK_COMBO_BOX(window->EncryptionCombo))>0&&
                yon_char_is_empty(hash)&&!yon_char_is_empty(hash_command)){
		gtk_widget_set_sensitive(window->HashBox,1);
		gtk_widget_set_sensitive(window->PasswordBox,1);
		gtk_widget_set_sensitive(window->NoEncriptionCheck,1);
	} else if (!yon_char_is_empty(hash)&&!yon_char_is_empty(hash_command)) {
		gtk_widget_set_sensitive(window->HashBox,1);
		gtk_widget_set_sensitive(window->PasswordBox,0);
		gtk_widget_set_sensitive(window->NoEncriptionCheck,0);
	} else {
		gtk_widget_set_sensitive(window->HashBox,0);
		gtk_widget_set_sensitive(window->PasswordBox,1);
	}
}

void on_password_changed(GtkWidget *, yon_password_window *window);

void yon_password_function_set(yon_password_window *window, double *password_func){
    window->strength_func = password_func;
    g_signal_connect(G_OBJECT(window->PasswordEntry),"changed",G_CALLBACK(on_password_changed),window);
    gtk_widget_show(window->PasswordStrengthProgress);
}

void on_password_accept(GtkWidget *,dictionary *dict){
    yon_password_window *window = yon_dictionary_get_data(dict->first,yon_password_window*);
    GtkWidget *target = yon_dictionary_get_data(dict->first->next,GtkWidget*);

    int encription_active = gtk_combo_box_get_active(GTK_COMBO_BOX(window->EncryptionCombo));
    char *final = NULL;
    if (encription_active <1||gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(window->NoEncriptionCheck))){
        final = yon_password_unencrypted_password_get(window);

        if (!final) return;
    } else {
        final = yon_password_hash_get(window);
        if (!final) return;
    }
    gtk_entry_set_text(GTK_ENTRY(target),final);
    gtk_widget_destroy(window->Window);
}

void on_password_changed(GtkWidget *, yon_password_window *window){
    if (window->strength_func){
        const char *password_str = gtk_entry_get_text(GTK_ENTRY(window->PasswordEntry));
        double strength = ((double(*)(yon_password_window *,const char*))window->strength_func)(window,password_str);
    }
}

yon_password_window *yon_password_window_new(){
    GtkBuilder *builder = gtk_builder_new_from_resource(ui_glade_path_password);
    yon_password_window *window = malloc(sizeof(yon_password_window));
    memset(window,0,sizeof(yon_password_window));
    window->Window = yon_gtk_builder_get_widget(builder,"PasswordWindow");
    window->HeadLabel = yon_gtk_builder_get_widget(builder,"userTitleNameLabel");
    window->StatusBox = yon_gtk_builder_get_widget(builder,"StatusBox");
    window->PasswordEntry = yon_gtk_builder_get_widget(builder,"PasswordEntry");
    window->RepeatPasswordEntry = yon_gtk_builder_get_widget(builder,"RepeatPasswordEntry");
    window->EncryptionCombo = yon_gtk_builder_get_widget(builder,"EncryptionCombo");
    window->NoEncriptionCheck = yon_gtk_builder_get_widget(builder,"NoEncriptionCheck");
    window->PasswordHashEntry = yon_gtk_builder_get_widget(builder,"PasswordHashEntry");
    window->PasswordStrengthProgress= yon_gtk_builder_get_widget(builder,"PasswordStrengthProgress");
    window->UserCancelButton = yon_gtk_builder_get_widget(builder,"UserCancelButton");
    window->AcceptButton = yon_gtk_builder_get_widget(builder,"UserOkButton");
    window->PasswordBox = yon_gtk_builder_get_widget(builder,"PasswordBox");
    window->PasswordTooltipPopover = yon_gtk_builder_get_widget(builder,"PasswordTooltipPopover");
    window->HashBox = yon_gtk_builder_get_widget(builder,"HashBox");

    window->old_password=NULL;
    g_signal_connect(G_OBJECT(window->UserCancelButton),"clicked",G_CALLBACK(on_subwindow_close),NULL);
    g_signal_connect(G_OBJECT(window->EncryptionCombo),"changed",G_CALLBACK(on_password_hash_sensitiveness),window);
    g_signal_connect(G_OBJECT(window->NoEncriptionCheck),"toggled",G_CALLBACK(on_password_hash_sensitiveness),window);
    g_signal_connect(G_OBJECT(window->PasswordHashEntry),"changed",G_CALLBACK(on_password_hash_sensitiveness),window);
    g_signal_connect(G_OBJECT(window->PasswordEntry),"changed",G_CALLBACK(on_password_hash_sensitiveness),window);
    g_signal_connect(G_OBJECT(window->RepeatPasswordEntry),"changed",G_CALLBACK(on_password_hash_sensitiveness),window);
	g_signal_connect(G_OBJECT(window->PasswordEntry),"focus-in-event",G_CALLBACK(on_password_focus_event),window);
	g_signal_connect(G_OBJECT(window->PasswordEntry),"focus-out-event",G_CALLBACK(on_password_focus_out_event),window);
	g_signal_connect(G_OBJECT(window->PasswordEntry),"enter-notify-event",G_CALLBACK(on_password_tooltip_event),window);
	g_signal_connect(G_OBJECT(window->PasswordEntry),"leave-notify-event",G_CALLBACK(on_password_tooltip_out_event),window);
    gtk_widget_show(window->Window);
    return window;
}

yon_password_window *yon_password_open(GtkEntry *target){
    g_return_val_if_fail(GTK_IS_ENTRY(target),NULL);

    yon_password_window *dialog = yon_password_window_new();
    char *icon_name = yon_char_unite("com.ublinux.",template_app_information.app_tech_name,NULL);
    yon_gtk_window_setup(GTK_WINDOW(dialog->Window),GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(target))),_PASSWORD_TITLE_LABEL,icon_name,"password_window");
    free(icon_name);

    g_signal_connect(G_OBJECT(dialog->NoEncriptionCheck),"toggled",G_CALLBACK(yon_hash_entry_sensitiveness_update),dialog);
    g_signal_connect(G_OBJECT(dialog->EncryptionCombo),"changed",G_CALLBACK(yon_hash_entry_sensitiveness_update),dialog);

    yon_gtk_entry_set_password_visibility_icon(GTK_ENTRY(dialog->PasswordEntry));
    yon_gtk_entry_set_password_visibility_icon(GTK_ENTRY(dialog->PasswordHashEntry));
    yon_gtk_entry_set_password_visibility_icon(GTK_ENTRY(dialog->RepeatPasswordEntry));

    char *old_password = yon_char_new(gtk_entry_get_text(target));
    char *hash_type = NULL;
    if (!yon_char_is_empty(old_password)&&strstr(old_password,"|")){
        hash_type = yon_char_divide(old_password,6);
        gtk_combo_box_set_active_id(GTK_COMBO_BOX(dialog->EncryptionCombo),hash_type);
    }
    if (!yon_char_is_empty(old_password)&&(strlen(old_password)==128||strlen(old_password)==64)){
        dialog->old_password = old_password;
        gtk_entry_set_text(GTK_ENTRY(dialog->PasswordHashEntry),old_password);
    } else if (!yon_char_is_empty(old_password)){
        dialog->old_password = old_password;
        gtk_entry_set_text(GTK_ENTRY(dialog->PasswordEntry),old_password);
        gtk_entry_set_text(GTK_ENTRY(dialog->RepeatPasswordEntry),old_password);
    }
    dictionary *dict = NULL;
    yon_dictionary_add_or_create_if_exists_with_data(dict,"window",dialog);
    yon_dictionary_add_or_create_if_exists_with_data(dict,"target",target);
    g_signal_connect(G_OBJECT(dialog->AcceptButton),"clicked",G_CALLBACK(on_password_accept),dict);
    g_signal_connect(G_OBJECT(dialog->EncryptionCombo),"changed",G_CALLBACK(on_password_encryption_changed),dialog);
    return dialog;
}