import asyncio
import os
from shlex import join


class CommandResult:
    def __init__(self, stdout, stderr, returncode):
        self.stdout = stdout.decode().strip()
        self.stderr = stderr.decode().strip()
        self.returncode = returncode


class PlayerctlProcess:
    def __init__(self, proc, debug=False):
        self.queue = asyncio.Queue()
        self.proc = proc

        async def reader(stream):
            while True:
                line = await stream.readline()
                if not line:
                    break
                line = line.decode().strip()
                if 'playerctl-DEBUG:' in line:
                    print(line)
                else:
                    self.queue.put_nowait(line)

        async def printer(stream):
            while True:
                line = await stream.readline()
                print(line)
                if not line:
                    break

        asyncio.get_event_loop().create_task(reader(proc.stdout))
        # asyncio.get_event_loop().create_task(printer(proc.stderr))

    def running(self):
        return self.proc.returncode is None


class PlayerctlCli:
    def __init__(self, bus_address=None, debug=False):
        self.bus_address = bus_address
        self.debug = debug
        self.proc = None

    async def _start(self, cmd):
        env = os.environ.copy()
        shell_cmd = f'playerctl {cmd}'

        if self.bus_address:
            env['DBUS_SESSION_BUS_ADDRESS'] = self.bus_address
        if self.debug:
            env['G_MESSAGES_DEBUG'] = 'playerctl'

        return await asyncio.create_subprocess_shell(
            shell_cmd,
            env=env,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE)

    async def start(self, cmd):
        proc = await self._start(cmd)
        return PlayerctlProcess(proc)

    async def run(self, cmd):
        proc = await self._start(cmd)
        stdout, stderr = await proc.communicate()
        await proc.wait()
        return CommandResult(stdout, stderr, proc.returncode)

    async def list(self, players=[], ignored=[]):
        args = ['--list-all']

        if players:
            args.extend(['--player', ','.join(players)])

        if ignored:
            args.extend(['--ignored-players', ','.join(ignored)])

        cmd = await self.run(join(args))
        assert cmd.returncode == 0, cmd.stderr
        return cmd.stdout.splitlines()
