#!/usr/bin/env python3

"""Classroom DVD control.

Discs are never played automatically. Inserting a disc only produces a
notification and changes the dock icon; playback always starts from a
deliberate press of the DVD button.
"""

import argparse
import os
import shutil
import subprocess
import sys

sys.path.insert(0, "/usr/local/lib/ekklesia-classroom")
sys.path.insert(
    0,
    os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "lib"),
)

import classroom_optical as optical  # noqa: E402

PLAYER = "vlc"
WINDOW_TOOL = "/usr/local/bin/classroom-window"


def notify(title, message, urgency="normal"):
    try:
        subprocess.Popen(
            [
                "notify-send",
                "--app-name=Ekklesia Classroom",
                f"--urgency={urgency}",
                "--",
                title,
                message,
            ],
            start_new_session=True,
        )
    except OSError:
        print(f"{title}: {message}", file=sys.stderr)


def player_command(device):
    """VLC, dressed down to look like an appliance rather than a desktop app.

    All of these are documented VLC 3.x options, verified against the
    3.0.23 build in Debian Trixie. No skin is involved: skins replace the
    interface wholesale and break DVD menu input, which is the one thing
    that has to keep working.

    Note that --no-qt-updates-notif, which earlier builds passed, is not
    an option in Debian's VLC and made it refuse to start at all.
    """
    return [
        PLAYER,
        # Fullscreen first: the disc opens straight onto the TV.
        "--fullscreen",
        # No menu bar or extended panels, and a dark window instead of
        # the default light grey one.
        "--qt-minimal-view",
        "--qt-dark-palette",
        # No orange cone, and no album-art panel, behind the video.
        "--no-qt-bgcone",
        # Nothing that behaves like a desktop application.
        "--no-qt-system-tray",
        "--no-qt-name-in-title",
        "--no-qt-video-autoresize",
        "--qt-notification=0",
        # Never offer to resume, and never accumulate a list of the
        # discs a classroom has played.
        "--qt-continue=0",
        "--no-qt-recentplay",
        # No first-run privacy dialog, no title banner over the video.
        "--no-qt-privacy-ask",
        "--no-video-title-show",
        # dvd:// selects VLC's dvdnav module, which is what provides the
        # disc menus. The Qt interface is kept for exactly that reason:
        # --intf dummy would be cleaner still but takes the keyboard and
        # mouse handling that menu navigation depends on with it.
        f"dvd://{device}",
    ]


def play(device):
    """Hand the disc to the player through the normal window toggle."""
    if shutil.which(PLAYER) is None:
        notify(
            "DVD",
            "The DVD player is not installed on this classroom computer.",
        )
        return 1

    subprocess.run(
        [
            WINDOW_TOOL,
            "toggle",
            "--match",
            "(?i)vlc",
            "--",
            *player_command(device),
        ]
    )

    return 0


def action_toggle(force_play=False):
    device = optical.default_device()

    if device is None:
        notify("DVD", "No DVD drive is connected to this classroom computer.")
        return 1

    status = optical.drive_status(device)

    if status == optical.CDS_DISC_OK:
        return play(device)

    if status == optical.CDS_DRIVE_NOT_READY:
        notify("DVD", "Reading the disc. Please try again in a moment.")
        return 1

    if status == optical.CDS_TRAY_OPEN:
        notify("DVD", "The disc tray is open. Insert a disc to get started.")
        return 1

    if force_play:
        return play(device)

    notify("DVD", "No disc is in the drive. Insert a disc to get started.")
    return 1


def action_status():
    device = optical.default_device()

    if device is None:
        print("drive: none")
        return 1

    status = optical.drive_status(device)

    print(f"drive: {device}")
    print(f"status: {optical.describe(status)}")
    print(f"player: {shutil.which(PLAYER) or 'not installed'}")

    if status == optical.CDS_DISC_OK:
        print(f"disc: {optical.disc_status(device)}")
        return 0

    return 1


def action_eject():
    device = optical.default_device()

    if device is None:
        notify("DVD", "No DVD drive is connected to this classroom computer.")
        return 1

    if not optical.eject(device):
        notify("DVD", "The disc could not be ejected. It may still be playing.")
        return 1

    return 0


def main():
    parser = argparse.ArgumentParser(description="Classroom DVD control.")
    subparsers = parser.add_subparsers(dest="action", required=True)

    subparsers.add_parser("toggle", help="Dock button behaviour")
    subparsers.add_parser("play", help="Start playback even if the drive is unsure")
    subparsers.add_parser("status", help="Report drive and disc state")
    subparsers.add_parser("eject", help="Open the disc tray")

    arguments = parser.parse_args()

    if arguments.action == "toggle":
        return action_toggle()

    if arguments.action == "play":
        return action_toggle(force_play=True)

    if arguments.action == "status":
        return action_status()

    return action_eject()


if __name__ == "__main__":
    sys.exit(main())
