#!/usr/bin/env python3
import gi.repository
gi.require_version("Gdk", "3.0")
from gi.repository import Gio, Gdk, GLib
import subprocess
import time
import os
import psutil
import re
gi.require_version('Libxfce4windowing', '0.0')
from gi.repository import Libxfce4windowing

"""
Budgie TakeaBreak
Author: Jacob Vlijm
Copyright © 2017-2022 Ubuntu Budgie Developers
Website=https://ubuntubudgie.org
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or any later version. This
program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. You
should have received a copy of the GNU General Public License along with this
program.  If not, see <http://www.gnu.org/licenses/>.
"""


dcpath = "/com/solus-project/budgie-panel/applets/"
tab_key = "org.ubuntubudgie.plugins.takeabreak"
user = os.environ["USER"]
tab_settings = Gio.Settings.new(tab_key)
# get current settings
auto_unlock = tab_settings.get_boolean("unlockafterbreak")
if Libxfce4windowing.windowing_get() == Libxfce4windowing.Windowing.WAYLAND:
    wayland = True
else:
    wayland = False
if auto_unlock and wayland:
    # hacky workaround for lack of unlock option in wayland
    auto_unlock = False

awaketime = tab_settings.get_int("awaketime") * 60
sleeptime = tab_settings.get_int("sleeptime") * 60
mode = tab_settings.get_string("mode")
if mode == "dim" and wayland:
    # hacky workaround for the lack of dim support in wayland
    mode = "message"
notify_msg = tab_settings.get_boolean("showmessage")
notify_time = 15
from_unidle = tab_settings.get_boolean("smartresume")
message = "Break in " + str(notify_time) + " seconds"
tabcountdown_path = os.path.dirname(os.path.abspath(__file__))


def get_idle():
    return int(subprocess_tasks("getval", ["xprintidle"], 0))


def idle_sleep():
    curr_idle1 = get_idle()
    while True:
        time.sleep(3)
        curr_idle2 = get_idle()
        if curr_idle2 <= curr_idle1:
            break
        else:
            curr_idle1 = curr_idle2


def subprocess_tasks(task, command_list, fallbackval=None):
    if task == "getval":
        try:
            return subprocess.check_output(command_list).decode("utf-8")
        except Exception:
            print("unable to get result from" + str(command_list))
            return fallbackval
    elif task == "run_sync":
        try:
            subprocess.call(command_list)
        except Exception:
            pass
    elif task == "run_async":
        try:
            subprocess.Popen(command_list)
        except Exception:
            pass


def write_nextbreak():
    next_break = time.time() + awaketime
    tmp = os.getenv("XDG_RUNTIME_DIR") \
        if "XDG_RUNTIME_DIR" in os.environ else os.getenv("HOME")
    nextbreakfile = os.path.join(tmp, ".nextbreak")
    open(nextbreakfile, "wt").write(str(next_break))


def sendmessage(title, message, icon=""):
    subprocess.Popen(["notify-send", "-i", icon, title, message])


def get_wlr_randr_outputs():
    try:
        # Run wlr-randr and capture output
        result = subprocess.run(['wlr-randr'],
                                capture_output=True,
                                text=True,
                                check=True)
        output = result.stdout

        # Extract output names (lines starting with alphanumeric characters)
        output_names = []
        for line in output.splitlines():
            # Match lines starting with an output name (e.g., HDMI-A-1, eDP-1)
            match = re.match(r'^[a-zA-Z0-9\-]+', line)
            if match:
                output_names.append(match.group(0))

        return output_names

    except subprocess.CalledProcessError as e:
        print(f"Error running wlr-randr: {e}")
        return []
    except FileNotFoundError:
        print("wlr-randr not found. Ensure it is installed and in your PATH.")
        return []


def take_a_break():
    gdkdisplay = Gdk.Display.get_default()
    screens = [
        gdkdisplay.get_monitor(n).get_model() for n in range(
            gdkdisplay.get_n_monitors()
        )]
    output_name = ""

    if wayland:
        output_name = get_wlr_randr_outputs()[0]
    if mode == "message":
        command = tabcountdown_path + "/message_window"
        subprocess_tasks("run_async", [command, str(sleeptime)])
    else:
        for scr in screens:
            if mode == "rotate":
                if wayland:
                    subprocess_tasks(
                        "run_sync",
                        ["wlr-randr",
                         "--output",
                         output_name,
                         "--transform",
                         "180"]
                    )
                else:
                    subprocess_tasks(
                        "run_sync",
                        ["xrandr", "--output", scr, "--rotate", "inverted"]
                    )
            elif mode == "dim":
                subprocess_tasks(
                    "run_sync",
                    ["xrandr", "--output", scr, "--brightness", "0.1"]
                )
            elif mode == "lock":
                if wayland:
                    subprocess_tasks(
                        "run_async",
                        ["dbus-send",
                         "--type=method_call",
                         "--dest=org.buddiesofbudgie.BudgieScreenlock",
                         "/org/buddiesofbudgie/Screenlock",
                         "org.buddiesofbudgie.BudgieScreenlock.Lock"])
                else:
                    subprocess_tasks(
                        "run_async",
                        ["gnome-screensaver-command", "-l"])
    time.sleep(sleeptime)
    for scr in screens:
        if auto_unlock:
            subprocess_tasks(
                "run_async",
                ["gnome-screensaver-command", "-d"]
            )
        time.sleep(2)
        if mode == "rotate":
            if wayland:
                subprocess_tasks(
                    "run_sync",
                    ["wlr-randr",
                     "--output",
                     output_name,
                     "--transform",
                     "normal"]
                )
            else:
                subprocess_tasks(
                    "run_sync",
                    ["xrandr", "--output", scr, "--rotate", "normal"]
                )
            time.sleep(0.2)
        elif mode == "dim":
            subprocess_tasks(
                "run_sync",
                ["xrandr", "--output", scr, "--brightness", "1"]
            )
            time.sleep(0.2)
    if from_unidle:
        idle_sleep()


if from_unidle:
    idle_sleep()


def lockscreen_check():
    lockproc = "gnome-screensaver-dialog"
    try:
        return lockproc in (p.name() for p in psutil.process_iter())
    except psutil.NoSuchProcess:
        return False


while True:
    write_nextbreak()
    time.sleep(awaketime - notify_time)
    if notify_msg:
        sendmessage("Take a break", message, "takeabreak-symbolic")
    time.sleep(notify_time)
    take_a_break()
