import asyncio
import logging
import os

import secretstorage

from vorta.keyring.abc import VortaKeyring

logger = logging.getLogger(__name__)

LABEL_TEMPLATE = "Vorta Backup Repo {repo_url}"


class VortaSecretStorageKeyring(VortaKeyring):
    """A wrapper for the secretstorage package to support the custom keyring backend"""

    def __init__(self):
        """
        Test whether DBus and a SecretStorage provider are available.
        """
        try:
            self.connection = secretstorage.dbus_init()
        except secretstorage.exceptions.SecretServiceNotAvailableException as e:
            logger.debug("SecretStorage provider or DBus daemon is not available.")
            raise e
        asyncio.set_event_loop(asyncio.new_event_loop())
        self.collection = secretstorage.get_default_collection(self.connection)

    def set_password(self, service, repo_url, password):
        """
        Writes a password to the underlying store.
        """
        if self.is_unlocked:
            asyncio.set_event_loop(asyncio.new_event_loop())
            attributes = {
                'application': 'Vorta',
                'service': service,
                'repo_url': repo_url,
                'xdg:schema': 'org.freedesktop.Secret.Generic',
            }
            self.collection.create_item(
                LABEL_TEMPLATE.format(repo_url=repo_url),
                attributes,
                password,
                replace=True,
            )
            logger.debug(f"Saved password for repo {repo_url}")

    def delete_password(self, service, repo_url):
        if self.is_unlocked:
            asyncio.set_event_loop(asyncio.new_event_loop())
            attributes = {
                'application': 'Vorta',
                'service': service,
                'repo_url': repo_url,
            }
            items = list(self.collection.search_items(attributes))
            for item in items:
                try:
                    item.delete()
                    logger.debug(f"Deleted password for repo {repo_url}")
                except Exception as e:
                    logger.debug(f"Failed to delete password for repo {repo_url}: {e}")

    def get_password(self, service, repo_url):
        """
        Retrieve a password from the underlying store. Return None if not found.
        """
        if self.is_unlocked:
            asyncio.set_event_loop(asyncio.new_event_loop())
            attributes = {
                'application': 'Vorta',
                'service': service,
                'repo_url': repo_url,
            }
            items = list(self.collection.search_items(attributes))
            logger.debug('Found %i passwords matching repo URL.', len(items))
            if len(items) > 0:
                item = items[0]
                if item.is_locked() and item.unlock():
                    return None
                logger.debug(f"Retrieved password for repo {repo_url}")
                return item.get_secret().decode("utf-8")
        return None

    @property
    def is_unlocked(self):
        # unlock() will return True if the unlock prompt is dismissed
        return not (self.collection.is_locked() and self.collection.unlock())

    @classmethod
    def get_priority(cls):
        return 6 if "GNOME" in os.getenv("XDG_CURRENT_DESKTOP", "") else 5

    @property
    def is_system(self):
        return True
