import logging

from defence360agent.contracts.license import LicenseCLN
from defence360agent.utils import (
    OsReleaseInfo,
    check_run,
    run,
    system_packages_info,
)
from im360.subsys.features.hardened_php import get_hardened_php_feature
from defence360agent.subsys.features.kernel_care import KernelCare

logger = logging.getLogger(__name__)


INSTALL_IE_CMD = (
    "wget -qq -O -"
    " https://repo.imunify360.cloudlinux.com/defence360/imunifyemail-deploy.sh"
    " | bash"
)


def list_feature_types():
    if OsReleaseInfo.id_like() & OsReleaseInfo.RHEL_FEDORA_CENTOS:
        return (KernelCare, get_hardened_php_feature())
    else:
        return ()


def get_applicable_features():
    return {
        "hardened-php": get_hardened_php_feature(),
        "kernelcare": KernelCare,
    }


def update_features_repos(op):
    """
    Features repo-files depends on server_id, so it should be actual
    after every registration operation
    :param str op: generate_repo/remove_repo
    """
    for feature in list_feature_types():
        method_to_call = getattr(feature(), op, None)
        if callable(method_to_call):
            method_to_call()


async def update_repos():
    if LicenseCLN.is_valid():
        # Update credentials in repos config
        logger.info("Updating repositories configuration with new credentials")
        update_features_repos("generate_repo")
    else:
        # Disable CLN repos for invalid license
        logger.warning(
            "License is invalid. Repositories for features will be disabled"
        )
        update_features_repos("remove_repo")


class IMEmailWrapper:
    PKG_NAME = "imunifyemail"

    @classmethod
    async def install(cls) -> None:
        """Installs imunifyemail."""
        await check_run(INSTALL_IE_CMD, shell=True)

    @classmethod
    async def ensure_installed(cls) -> None:
        """Installs imunifyemail if not installed."""
        imunify_email_package = await system_packages_info([cls.PKG_NAME])
        if imunify_email_package[cls.PKG_NAME] is None:
            await cls.install()

    @classmethod
    async def is_enabled(cls) -> bool:
        """Checks whether imunifyemail is enabled."""
        try:
            returncode, out, err = await run(["/usr/sbin/ie-config", "is-on"])
        except FileNotFoundError:
            # not installed
            return False
        return returncode == 0

    @classmethod
    async def ensure_enabled(cls) -> None:
        """Enables imunifyemail if disabled."""
        if not await cls.is_enabled():
            await check_run(["/usr/sbin/ie-config", "-v", "enable"])

    @classmethod
    async def ensure_disabled(cls) -> None:
        """Disables imunifyemail if enabled."""
        if await cls.is_enabled():
            await check_run(
                ["/usr/sbin/ie-config", "-v", "disable"],
            )


async def update_im_email():
    """
    Enables or disables im-email based on active license permissions.
    """
    if LicenseCLN.has_permission("IM_EMAIL"):
        await IMEmailWrapper.ensure_installed()
        await IMEmailWrapper.ensure_enabled()
    else:
        await IMEmailWrapper.ensure_disabled()
