#!/usr/bin/python3

import sys
import gi
import subprocess
import threading
import time
import os
import pwd
import re

import logging

gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, Adw, Gdk, Gio, GLib, Graphene
from PIL import Image
import random
import string

SUPPORT_URL = "https://t.me/UncomOS/"
IMAGES_DIR = "/usr/share/uncom-update/pixmaps/"
IMAGE_LIGHT = "gnome45-light.png"
IMAGE_DARK = "gnome45-dark.png"

class MainWindow(Gtk.ApplicationWindow):

    workDone = False

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # window
        self.set_default_size(800, 800)
        self.set_title("Обновление системы")
        self.set_resizable(False)

        self.main_box = Gtk.Box(spacing=0, orientation=Gtk.Orientation.VERTICAL)
        self.set_child(self.main_box)

        # box1
        self.box1 = Gtk.Box(spacing=5, orientation=Gtk.Orientation.VERTICAL)
        self.box1.set_margin_start(20)
        self.box1.set_margin_end(20)
        self.box1.set_margin_top(20)
        self.box1.set_margin_bottom(20)
        self.main_box.append(self.box1)  

        # box1 label1
        self.label1 = Gtk.Label()
        self.label1.set_markup("<big>Вышло обновление интерфейса для Uncom OS!</big>")
        self.label1.set_wrap(True)
        self.label1.set_justify(Gtk.Justification.CENTER)
        self.label1.set_xalign(0.5)
        self.box1.append(self.label1)

        # box_picture
        self.box_picture = Gtk.Box(spacing=0, orientation=Gtk.Orientation.VERTICAL)
        self.box_picture.set_margin_start(0)
        self.box_picture.set_margin_end(0)
        self.box_picture.set_margin_top(0)
        self.box_picture.set_margin_bottom(0)
        self.main_box.append(self.box_picture)  

        # box_picture picture1
        self.picture1 = Gtk.Picture.new_for_filename(IMAGES_DIR + IMAGE_LIGHT)
        self.box_picture.append(self.picture1)

        # box2
        self.box2 = Gtk.Box(spacing=10, orientation=Gtk.Orientation.VERTICAL)
        self.box2.set_margin_start(20)
        self.box2.set_margin_end(20)
        self.box2.set_margin_top(20)
        self.box2.set_margin_bottom(20)
        self.main_box.append(self.box2) 

        # box2 label2
        self.label2 = Gtk.Label(label="Перед обновлением убедитесь, что не запущены другие программы установки и удаления ПО. Потребуется соединение с интернетом. Ноутбук необходимо подключить к питанию.")
        self.label2.set_wrap(True)
        self.label2.set_justify(Gtk.Justification.CENTER)
        self.label2.set_xalign(0.5)
        self.box2.append(self.label2)

        # box3
        self.box3 = Gtk.Box(spacing=10, orientation=Gtk.Orientation.VERTICAL)
        self.box2.set_margin_start(20)
        self.box2.set_margin_end(20)
        self.box2.set_margin_top(20)
        self.box2.set_margin_bottom(20)
        self.main_box.append(self.box3)

        # box3 box_buttons
        self.box_buttons = Gtk.Box(spacing=5, orientation=Gtk.Orientation.HORIZONTAL)
        self.box_buttons.set_margin_top(20)
        self.box3.append(self.box_buttons)

        self.button_cancel = Gtk.Button(label="Установить обновление позже")
        self.button_cancel.set_hexpand(True)
        self.button_cancel.set_halign(Gtk.Align.END)
        self.button_cancel.connect("clicked", self.on_button_cancel_clicked)
        self.box_buttons.append(self.button_cancel)

        self.button_apply = Gtk.Button(label="Обновить Uncom OS (около 15 минут)")
        self.button_apply.set_hexpand(True)
        self.button_apply.set_halign(Gtk.Align.START)
        self.button_apply.connect("clicked", self.on_button_update_clicked)
        self.box_buttons.append(self.button_apply)

        # box3 spinner
        self.spinner = Gtk.Spinner()
        self.box3.append(self.spinner)
        self.spinner.set_visible(True)
        self.spinner.set_vexpand(True)
        # self.spinner.start()

        # box3 label_A
        self.label_A = Gtk.Label(label="Вы не сможете вернуться на предыдущую версию интерфейса.")
        self.label_A.set_valign(Gtk.Align.END)
        self.label_A.set_wrap(True)
        self.box3.append(self.label_A)

        # box3 button_support
        self.button_support = Gtk.LinkButton(uri=SUPPORT_URL, label="Техподдержка")
        self.label_A.set_valign(Gtk.Align.END)
        self.box3.append(self.button_support)

        # end of UI formation

        self.header = Gtk.HeaderBar()
        self.set_titlebar(self.header)

        action = Gio.SimpleAction.new("show_about_dialog", None)
        action.connect("activate", self.show_about_dialog)
        self.add_action(action)

        # Create a new menu, containing that action
        menu = Gio.Menu.new()
        menu.append("О приложении", "win.show_about_dialog")

        # Create a popover
        self.popover = Gtk.PopoverMenu()  # Create a new popover menu
        self.popover.set_menu_model(menu)

        # Create a menu button
        self.hamburger = Gtk.MenuButton()
        self.hamburger.set_popover(self.popover)
        self.hamburger.set_icon_name("open-menu-symbolic")  # Give it a nice icon

        # Add menu button to the header bar
        self.header.pack_start(self.hamburger)

        # def show_message_info(message):
        #     self.dialog = Gtk.MessageDialog(
        #         transient_for=self,
        #         message_type=Gtk.MessageType.INFO,
        #         buttons=Gtk.ButtonsType.OK,
        #         text=message,
        #     )

        #     def close_dialog(self, app):
        #         self.destroy()

        #     self.dialog.connect('response', close_dialog)
        #     self.dialog.set_modal(self)
        #     self.dialog.show()
            

        # Update picture color when the theme variant changes
        Gtk.Settings.get_default().connect("notify::gtk-theme-name", self.on_theme_name_changed)
        self.update_picture_theme(Gtk.Settings().get_default().get_property("gtk-theme-name"))

    def on_theme_name_changed(self, settings, gparam):
        print("Theme name:", settings.get_property("gtk-theme-name"))
        self.update_picture_theme(settings.get_property("gtk-theme-name"))

    def update_picture_theme(self, themename):
        if "dark" in themename:
            self.picture1.set_filename(IMAGES_DIR + IMAGE_DARK)
        else:
            self.picture1.set_filename(IMAGES_DIR + IMAGE_LIGHT)

    def show_about_dialog(self, action, param):
        print("Show about dialog")    
        self.about = Gtk.AboutDialog()
        self.about.set_program_name("Обновление системы")
        self.about.set_transient_for(self)  # Makes the dialog always appear in from of the parent window
        self.about.set_modal(self)  # Makes the parent window unresponsive while dialog is showing

        self.about.set_copyright("Copyright 2023 Uncom OS")
        self.about.set_license_type(Gtk.License.GPL_3_0)
        self.about.set_website("http://uncom.tech")
        self.about.set_website_label("Веб-страница")
        self.about.set_version("1.0")
        # The icon will need to be added to appropriate location
        # E.g. /usr/share/icons/hicolor/scalable/apps/org.example.example.svg
        self.about.set_logo_icon_name("uncom-update")
        self.about.set_visible(True)

    def on_work_done(self):
        print("on_work_done: work is done!")
        with open('/var/log/uncom-update.log') as f:
            for line in f:
                pass
            last_line = line
        logging.debug("on_work_done: last_line = %s", last_line)
        if "Final_success" in last_line:
            self.label_A.set_label("Обновление успешно установлено, перезагрузите компьютер.")
        else:
            self.label_A.set_label("Обновление завершено с ошибками: /var/log/uncom-update.log")

    def on_button_cancel_clicked(self, button):
        print("Cancel clicked")
        exit(0)

    def on_button_update_clicked(self, button):
        print("Apply clicked, workDone =", self.workDone)
        logging.debug("Apply clicked, workDone = %s", self.workDone)

        # Disable the button while the command is running
        self.button_apply.set_sensitive(False)
        self.button_cancel.set_sensitive(False)

        # Hide the label and show the spinner
        self.label_A.set_visible(False)
        # self.spinner.set_visible(True)
        self.spinner.start()

        if self.workDone:
            ok_to_start = 0
        else:
            ok_to_start = subprocess.call(["/sbin/check_update_conditions"], shell=True, universal_newlines=True)
            print("check_update_conditions return code =", ok_to_start)

        logging.debug('ok_to_start = %s', ok_to_start)

        if (ok_to_start != 0):
            print("Can't start!")
            if (ok_to_start == 1):
                text_explain="Не удается обновить: нужен запуск от администратора."
            elif (ok_to_start == 2):
                text_explain="Не удается обновить: недоступен репозиторий Uncom OS, проверьте интернет."
            elif (ok_to_start == 3):
                text_explain="Не удается обновить: идёт работа с пакетами в другой программе."
            else:
                text_explain="Не удается обновить: неизвестная ошибка."

            print("Can't start, text_explain =", text_explain)
            self.label_A.set_label(text_explain)
            self.label_A.set_visible(True)
            self.spinner.stop()
            self.button_apply.set_sensitive(True)
            self.button_cancel.set_sensitive(True)
            return

        # Start the command execution in a separate thread
        def run_command():
            # Disable sleep mode
            # subprocess.call(["echo lock_me > /sys/power/wake_lock"])
            # Run the command asynchronously
            subprocess.run(["/sbin/do-uncom-update"])
            self.workDone = True
            # After the command finishes, hide the progress bar and re-enable the button
            # GLib.idle_add(lambda: self.spinner.set_visible(False))
            GLib.idle_add(lambda: self.spinner.stop())
            GLib.idle_add(lambda: self.button_apply.set_sensitive(True))
            GLib.idle_add(lambda: self.button_apply.set_label("Перезагрузить сейчас"))
            GLib.idle_add(lambda: self.button_cancel.set_sensitive(True))
            GLib.idle_add(lambda: self.button_cancel.set_label("Перезагрузить позже"))
            GLib.idle_add(lambda: self.label_A.set_visible(True))
            GLib.idle_add(lambda: self.on_work_done())
            # Enable sleep mode back
            # subprocess.call(["echo lock_me > /sys/power/wake_unlock"])

        def run_reboot():
            print("Rebooting...")
            logging.debug('Rebooting')
            subprocess.run(["/sbin/reboot"])

        if self.workDone:
            thread = threading.Thread(target=run_reboot)
            thread.start()
            exit(0)
        else:
            thread = threading.Thread(target=run_command)
            thread.start()



class MyApp(Gtk.Application):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.connect('activate', self.on_activate)

    def on_activate(self, app):
        self.win = MainWindow(application=app)
        self.win.present()

print("Running application as: " + os.getlogin())
logging.basicConfig(filename='/var/log/uncom-update.log', encoding='utf-8', level=logging.DEBUG)

main_app = MyApp(application_id="tech.uncom.update")
main_app.run()
