"""AppArmor control for host."""
import logging
import shutil
from pathlib import Path

from ..coresys import CoreSysAttributes
from ..exceptions import DBusError, HostAppArmorError
from ..utils.apparmor import validate_profile

_LOGGER = logging.getLogger(__name__)

SYSTEMD_SERVICES = {"hassos-apparmor.service", "hassio-apparmor.service"}


class AppArmorControl(CoreSysAttributes):
    """Handle host AppArmor controls."""

    def __init__(self, coresys):
        """Initialize host power handling."""
        self.coresys = coresys
        self._profiles = set()
        self._service = None

    @property
    def available(self):
        """Return True if AppArmor is available on host."""
        return self._service is not None

    def exists(self, profile):
        """Return True if a profile exists."""
        return profile in self._profiles

    async def _reload_service(self):
        """Reload internal service."""
        try:
            await self.sys_host.services.reload(self._service)
        except DBusError as err:
            _LOGGER.error("Can't reload %s: %s", self._service, err)

    def _get_profile(self, profile_name):
        """Get a profile from AppArmor store."""
        if profile_name not in self._profiles:
            _LOGGER.error("Can't find %s for removing", profile_name)
            raise HostAppArmorError()
        return Path(self.sys_config.path_apparmor, profile_name)

    async def load(self):
        """Load available profiles."""
        for content in self.sys_config.path_apparmor.iterdir():
            if not content.is_file():
                continue
            self._profiles.add(content.name)

        # Is connected with systemd?
        _LOGGER.info("Load AppArmor Profiles: %s", self._profiles)
        for service in SYSTEMD_SERVICES:
            if not self.sys_host.services.exists(service):
                continue
            self._service = service

        # Load profiles
        if self.available:
            await self._reload_service()
        else:
            _LOGGER.info("AppArmor is not enabled on host")

    async def load_profile(self, profile_name, profile_file):
        """Load/Update a new/exists profile into AppArmor."""
        if not validate_profile(profile_name, profile_file):
            _LOGGER.error("Profile is not valid with name %s", profile_name)
            raise HostAppArmorError()

        # Copy to AppArmor folder
        dest_profile = Path(self.sys_config.path_apparmor, profile_name)
        try:
            shutil.copy(profile_file, dest_profile)
        except OSError as err:
            _LOGGER.error("Can't copy %s: %s", profile_file, err)
            raise HostAppArmorError() from None

        # Load profiles
        _LOGGER.info("Add or Update AppArmor profile: %s", profile_name)
        self._profiles.add(profile_name)
        if self.available:
            await self._reload_service()

    async def remove_profile(self, profile_name):
        """Remove a AppArmor profile."""
        profile_file = self._get_profile(profile_name)

        # Only remove file
        if not self.available:
            try:
                profile_file.unlink()
            except OSError as err:
                _LOGGER.error("Can't remove profile: %s", err)
                raise HostAppArmorError()
            return

        # Marks als remove and start host process
        remove_profile = Path(self.sys_config.path_apparmor, "remove", profile_name)
        try:
            profile_file.rename(remove_profile)
        except OSError as err:
            _LOGGER.error("Can't mark profile as remove: %s", err)
            raise HostAppArmorError()

        _LOGGER.info("Remove AppArmor profile: %s", profile_name)
        self._profiles.remove(profile_name)
        await self._reload_service()

    def backup_profile(self, profile_name, backup_file):
        """Backup A profile into a new file."""
        profile_file = self._get_profile(profile_name)

        try:
            shutil.copy(profile_file, backup_file)
        except OSError as err:
            _LOGGER.error("Can't backup profile %s: %s", profile_name, err)
            raise HostAppArmorError()
