# -*- coding: utf-8 -*-
# This file is part of beets.
# Copyright 2016, David Hamp-Gonsalves
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

"""Send the results of a query to the configured music player as a playlist.
"""
from __future__ import division, absolute_import, print_function

from beets.plugins import BeetsPlugin
from beets.ui import Subcommand
from beets import config
from beets import ui
from beets import util
from os.path import relpath
from tempfile import NamedTemporaryFile

# Indicate where arguments should be inserted into the command string.
# If this is missing, they're placed at the end.
ARGS_MARKER = '$args'


class PlayPlugin(BeetsPlugin):

    def __init__(self):
        super(PlayPlugin, self).__init__()

        config['play'].add({
            'command': None,
            'use_folders': False,
            'relative_to': None,
            'raw': False,
            # Backwards compatibility. See #1803 and line 74
            'warning_threshold': -2,
            'warning_treshold': 100,
        })

    def commands(self):
        play_command = Subcommand(
            'play',
            help=u'send music to a player as a playlist'
        )
        play_command.parser.add_album_option()
        play_command.parser.add_option(
            u'-A', u'--args',
            action='store',
            help=u'add additional arguments to the command',
        )
        play_command.func = self.play_music
        return [play_command]

    def play_music(self, lib, opts, args):
        """Execute query, create temporary playlist and execute player
        command passing that playlist, at request insert optional arguments.
        """
        command_str = config['play']['command'].get()
        if not command_str:
            command_str = util.open_anything()
        use_folders = config['play']['use_folders'].get(bool)
        relative_to = config['play']['relative_to'].get()
        raw = config['play']['raw'].get(bool)
        warning_threshold = config['play']['warning_threshold'].get(int)
        # We use -2 as a default value for warning_threshold to detect if it is
        # set or not. We can't use a falsey value because it would have an
        # actual meaning in the configuration of this plugin, and we do not use
        # -1 because some people might use it as a value to obtain no warning,
        # which wouldn't be that bad of a practice.
        if warning_threshold == -2:
            # if warning_threshold has not been set by user, look for
            # warning_treshold, to preserve backwards compatibility. See #1803.
            # warning_treshold has the correct default value of 100.
            warning_threshold = config['play']['warning_treshold'].get(int)

        if relative_to:
            relative_to = util.normpath(relative_to)

        # Add optional arguments to the player command.
        if opts.args:
            if ARGS_MARKER in command_str:
                command_str = command_str.replace(ARGS_MARKER, opts.args)
            else:
                command_str = u"{} {}".format(command_str, opts.args)

        # Perform search by album and add folders rather than tracks to
        # playlist.
        if opts.album:
            selection = lib.albums(ui.decargs(args))
            paths = []

            sort = lib.get_default_album_sort()
            for album in selection:
                if use_folders:
                    paths.append(album.item_dir())
                else:
                    paths.extend(item.path
                                 for item in sort.sort(album.items()))
            item_type = 'album'

        # Perform item query and add tracks to playlist.
        else:
            selection = lib.items(ui.decargs(args))
            paths = [item.path for item in selection]
            if relative_to:
                paths = [relpath(path, relative_to) for path in paths]
            item_type = 'track'

        item_type += 's' if len(selection) > 1 else ''

        if not selection:
            ui.print_(ui.colorize('text_warning',
                                  u'No {0} to play.'.format(item_type)))
            return

        # Warn user before playing any huge playlists.
        if warning_threshold and len(selection) > warning_threshold:
            ui.print_(ui.colorize(
                'text_warning',
                u'You are about to queue {0} {1}.'.format(
                    len(selection), item_type)))

            if ui.input_options(('Continue', 'Abort')) == 'a':
                return

        ui.print_(u'Playing {0} {1}.'.format(len(selection), item_type))
        if raw:
            open_args = paths
        else:
            open_args = [self._create_tmp_playlist(paths)]

        self._log.debug(u'executing command: {} {}', command_str,
                        b' '.join(open_args))
        try:
            util.interactive_open(open_args, command_str)
        except OSError as exc:
            raise ui.UserError(
                "Could not play the query: {0}".format(exc))

    def _create_tmp_playlist(self, paths_list):
        """Create a temporary .m3u file. Return the filename.
        """
        m3u = NamedTemporaryFile('wb', suffix='.m3u', delete=False)
        for item in paths_list:
            m3u.write(item + b'\n')
        m3u.close()
        return m3u.name
