"""Adds a `source_path` attribute to imported albums indicating from what path
the album was imported from. Also suggests removing that source path in case
you've removed the album from the library.

"""

import os
from pathlib import Path
from shutil import rmtree

from beets.dbcore.query import PathQuery
from beets.plugins import BeetsPlugin
from beets.ui import input_options
from beets.util.color import colorize


class ImportSourcePlugin(BeetsPlugin):
    """Main plugin class."""

    def __init__(self):
        """Initialize the plugin and read configuration."""
        super().__init__()
        self.config.add(
            {
                "suggest_removal": False,
            }
        )
        self.import_stages = [self.import_stage]
        self.register_listener("item_removed", self.suggest_removal)
        # In order to stop future removal suggestions for an album we keep
        # track of `mb_albumid`s in this set.
        self.stop_suggestions_for_albums = set()
        # During reimports (import --library) both the import_task_choice and
        # the item_removed event are triggered. The item_removed event is
        # triggered first. For the import_task_choice event we prevent removal
        # suggestions using the existing stop_suggestions_for_album mechanism.
        self.register_listener(
            "import_task_choice", self.prevent_suggest_removal
        )

    def prevent_suggest_removal(self, session, task):
        if task.skip:
            return
        for item in task.imported_items():
            if "mb_albumid" in item:
                self.stop_suggestions_for_albums.add(item.mb_albumid)

    def import_stage(self, _, task):
        """Event handler for albums import finished."""
        for item in task.imported_items():
            # During reimports (import --library), we prevent overwriting the
            # source_path attribute with the path from the music library
            if "source_path" in item:
                self._log.info(
                    "Preserving source_path of reimported item {}", item.id
                )
                continue
            item["source_path"] = item.path
            item.try_sync(write=False, move=False)

    def suggest_removal(self, item):
        """Prompts the user to delete the original path the item was imported from."""
        if (
            not self.config["suggest_removal"]
            or item.mb_albumid in self.stop_suggestions_for_albums
        ):
            return

        if "source_path" not in item:
            self._log.warning(
                "Item without source_path (probably imported before plugin "
                "usage): {}",
                item.filepath,
            )
            return

        srcpath = Path(os.fsdecode(item.source_path))
        if not srcpath.is_file():
            self._log.warning(
                "Original source file no longer exists or is not accessible: {}",
                srcpath,
            )
            return

        if not (
            os.access(srcpath, os.W_OK)
            and os.access(srcpath.parent, os.W_OK | os.X_OK)
        ):
            self._log.warning(
                "Original source file cannot be deleted (insufficient permissions): {}",
                srcpath,
            )
            return

        # We ask the user whether they'd like to delete the item's source
        # directory
        item_path = colorize("text_warning", item.filepath)
        source_path = colorize("text_warning", srcpath)

        print(
            f"The item:\n{item_path}\nis originated from:\n{source_path}\n"
            "What would you like to do?"
        )

        resp = input_options(
            [
                "Delete the item's source",
                "Recursively delete the source's directory",
                "do Nothing",
                "do nothing and Stop suggesting to delete items from this album",
            ],
            require=True,
        )

        # Handle user response
        if resp == "d":
            self._log.info(
                "Deleting the item's source file: {}",
                srcpath,
            )
            srcpath.unlink()

        elif resp == "r":
            self._log.info(
                "Searching for other items with a source_path attr containing: {}",
                srcpath.parent,
            )

            source_dir_query = PathQuery(
                "source_path",
                srcpath.parent,
                # The "source_path" attribute may not be present in all
                # items of the library, so we avoid errors with this:
                fast=False,
            )

            print("Doing so will delete the following items' sources as well:")
            for searched_item in item._db.items(source_dir_query):
                print(colorize("text_warning", searched_item.filepath))

            print("Would you like to continue?")
            continue_resp = input_options(
                ["Yes", "delete None", "delete just the File"],
                require=False,  # Yes is the a default
            )

            if continue_resp == "y":
                self._log.info(
                    "Deleting the item's source directory: {}",
                    srcpath.parent,
                )
                rmtree(srcpath.parent)

            elif continue_resp == "n":
                self._log.info("doing nothing - aborting hook function")
                return

            elif continue_resp == "f":
                self._log.info(
                    "removing just the item's original source: {}",
                    srcpath,
                )
                srcpath.unlink()

        elif resp == "s":
            self.stop_suggestions_for_albums.add(item.mb_albumid)

        else:
            self._log.info("Doing nothing")
