#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import dbus
import glob
import json
import os
import subprocess
import time
from concurrent.futures import ThreadPoolExecutor

from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib
from evdev import InputDevice, categorize, ecodes, KeyEvent

# Get from `bluetoothctl devices`
DEVICE_MAC = "00_08_E0_71_7E_95"
# Add anything mpv plays
FILES = [
    "https://st01.sslstream.dlf.de/dlf/01/high/opus/stream.opus",  # deutschlandfunk
    "http://streams.fluxfm.de/live/aac-64/audio/play.pls",         # fluxfm
    "http://forbes.streams.bassdrive.com:8132/listen.pls",         # bassdrive
]
MPV_IPC_SOCKET = "/tmp/mpv-radio.socket"

# Process if media player is running, None otherwise
PLAYER_PROCESS = None
# Index into FILES
CURRENT_FILE = 0
# DBus
DBUS_LOOP = DBusGMainLoop(set_as_default=True)
BUS = dbus.SystemBus()

THREADPOOL = ThreadPoolExecutor(max_workers=10)


def background(func):
    def swallow():
        try:
            func()
        except Exception as e:
            print("Func threw:", func.__name__, e)
    THREADPOOL.submit(swallow)


def player_command(*args):
    global PLAYER_PROCESS
    command=json.dumps({
        "command": args
    })
    command += "\n"
    command = command.encode("utf-8")
    print("player_command:", args, command)
    return subprocess.check_output(["socat", "-", "/tmp/mpv-radio.socket"],
                                   stderr=subprocess.STDOUT,
                                   input=command)

def start_player():
    global PLAYER_PROCESS
    global FILES
    assert PLAYER_PROCESS == None

    PLAYER_PROCESS = subprocess.Popen(["mpv", "--audio-device", "alsa/bluealsa",
                                       "--quiet",
                                       "--input-ipc-server=" + MPV_IPC_SOCKET,
                                       FILES[0]],
                                      stdout=open("/tmp/radio.log.stdout", "w+"),
                                      stderr=open("/tmp/radio.log.stderr", "w+"),
                                      stdin=subprocess.PIPE)

def stop_player():
    global PLAYER_PROCESS
    assert PLAYER_PROCESS != None
    try:
        PLAYER_PROCESS.terminate()
        print(PLAYER_PROCESS.communicate(timeout=5))
    except subprocess.TimeoutExpired:
        PLAYER_PROCESS.kill()
        print(PLAYER_PROCESS.communicate())
    PLAYER_PROCESS = None

def find_input_device():
    return max(glob.glob("/dev/input/event*"))

def handle_input_events():
    global CURRENT_FILE
    global FILES
    time.sleep(5)
    dev = InputDevice(find_input_device())
    for event in dev.read_loop():
        if event.type == ecodes.EV_KEY:
            print("event:", categorize(event))
            kev = KeyEvent(event)
            if kev.keystate == KeyEvent.key_up:
                print("next")
                CURRENT_FILE = (CURRENT_FILE + 1) % len(FILES)
                print(player_command("loadfile", FILES[CURRENT_FILE]))

def handle_connection_event(*args, **kwargs):
    obj = args[0]
    args = args[1]

    if obj == "org.bluez.MediaControl1":
        if args["Connected"]:
            print("connected")
            background(handle_input_events)
        else:
            print("disconnected")
            stop_player()


def handle_bluealsa_sink(*args, **kwargs):
    path = args[0]
    if path == "/org/bluealsa/hci0/dev_" + DEVICE_MAC + "/a2dpsrc/sink":
        print("a2dp sink connected")
        start_player()


BUS.add_signal_receiver(handle_connection_event,
                        bus_name="org.bluez",
                        dbus_interface="org.freedesktop.DBus.Properties",
                        path="/org/bluez/hci0/dev_" + DEVICE_MAC,
                        signal_name="PropertiesChanged")

BUS.add_signal_receiver(handle_bluealsa_sink,
                        bus_name="org.bluealsa",
                        dbus_interface="org.bluealsa.Manager1",
                        signal_name="PCMAdded")


try:
    loop = GLib.MainLoop()
    loop.run()
except KeyboardInterrupt:
    stop_player()
