import argparse
import re
import sys
from . import util
from .util import add_opt
from .syscontainers import OSTREE_PRESENT
from Atomic.backendutils import BackendUtils
from Atomic.discovery import RegistryInspectError
from time import gmtime, strftime

try:
    from . import Atomic
except ImportError:
    from atomic import Atomic # pylint: disable=relative-import

INSTALL_ARGS = ["run",
                "-t",
                "-i",
                "--rm",
                "--privileged",
                "-v", "/:/host",
                "--net=host",
                "--ipc=host",
                "--pid=host",
                "-e", "HOST=/host",
                "-e", "NAME=${NAME}",
                "-e", "IMAGE=${IMAGE}",
                "-e", "CONFDIR=/host/etc/${NAME}",
                "-e", "LOGDIR=/host/var/log/${NAME}",
                "-e", "DATADIR=/host/var/lib/${NAME}",
                "-e", "SYSTEMD_IGNORE_CHROOT=1", 
                "--name", "${NAME}",
                "${IMAGE}"]

ATOMIC_CONFIG = util.get_atomic_config()
_storage = ATOMIC_CONFIG.get('default_storage', "docker")

def cli(subparser):
    # atomic install
    installp = subparser.add_parser(
        "install", help=_("execute container image install method"),
        epilog="atomic install attempts to read the LABEL INSTALL field "
        "in the image, if it does not exist atomic will just pull "
        "the image on to your machine.  You could add a LABEL "
        "INSTALL command to your Dockerfile like: 'LABEL INSTALL "
        "%s'" % Install.print_install())
    installp.set_defaults(_class=Install, func='install')
    add_opt(installp)
    installp.add_argument("--storage", dest="storage", default=None,
                   help=_("Specify the storage. Default is currently '%s'.  You can"
                          " change the default by editing /etc/atomic.conf and changing"
                          " the 'default_storage' field." % _storage))
    installp.add_argument("-n", "--name", dest="name", default=None,
                          help=_("name of container"))
    installp.add_argument(
        "--display",
        default=False,
        action="store_true",
        help=_("preview the command that %s would execute") % sys.argv[0])
    installp.add_argument("image", help=_("container image"))
    if OSTREE_PRESENT:
        system_xor_user = installp.add_mutually_exclusive_group()
        system_xor_user.add_argument("--user", dest="user", action="store_true", default=False,
                                     help=_("install the image as an user image."))
        system_xor_user.add_argument("--system", dest="system",
                                     action='store_true', default=False,
                                     help=_('install a system container'))
        installp.add_argument("--system-package", dest="system_package", default="auto",
                              help=_('control how to install the package.  It accepts `auto`, `yes`, `no`, `build`'))
        installp.add_argument("--rootfs", dest="remote",
                              help=_("choose an existing exploded container/image to use "
                                     "its rootfs as a remote, read-only rootfs for the "
                                     "container to be installed"))
        installp.add_argument("--set", dest="setvalues",
                              action='append',
                              help=_("specify a variable in the VARIABLE=VALUE "
                                     "form for a system container"))
    installp.add_argument("args", nargs=argparse.REMAINDER,
                          help=_("additional arguments appended to the image "
                                 "install method"))


class Install(Atomic):
    def install(self):
        if self.args.debug:
            util.write_out(str(self.args))
        storage_set = False if self.args.storage is None else True
        storage = _storage if not storage_set else self.args.storage
        args_system = getattr(self.args, 'system', None)
        args_user= getattr(self.args, 'user', None)
        if (args_system or args_user) and storage != 'ostree' and storage_set:
            raise ValueError("The --system and --user options are only available for the 'ostree' storage.")
        be_utils = BackendUtils()
        try:
            # Check to see if the container already exists
            _, _ = be_utils.get_backend_and_container_obj(self.name)
            raise ValueError("A container '%s' is already present" % self.name)
        except ValueError:
            pass

        if self.user:
            if not util.is_user_mode():
                raise ValueError("--user does not work for privileged user")
            return self.syscontainers.install_user_container(self.image, self.name)
        if self.ostree_uri(self.image):
            return self.syscontainers.install(self.image, self.name)
        # Check if image exists
        str_backend = 'ostree' if self.args.system else self.args.storage or storage
        be = be_utils.get_backend_from_string(str_backend)
        img_obj = be.has_image(self.args.image)
        if img_obj and img_obj.is_system_type:
            be = be_utils.get_backend_from_string('ostree')

        if img_obj is None:
            # Unable to find the image locally, look remotely
            remote_image_obj = be.make_remote_image(self.args.image)
            # We found an atomic.type of system, therefore install it onto the ostree
            # backend
            if remote_image_obj.is_system_type and not storage_set:
                be_utils.message_backend_change('docker', 'ostree')
                be = be_utils.get_backend_from_string('ostree')
            be.pull_image(self.args.image, remote_image_obj, debug=self.args.debug)
            img_obj = be.has_image(self.image)

        if be.backend is not 'docker':
            if OSTREE_PRESENT and self.args.setvalues and not self.user and not self.system:
                raise ValueError("--set is valid only when used with --system or --user")

            # We need to fix this long term and get ostree
            # using the backend approach vs the atomic args
            be.syscontainers.set_args(self.args)
            return be.install(self.image, self.name)

        installation = None
        if storage == 'docker' and not args_system:
            if self.args.system_package == 'build':
                raise ValueError("'--system-package=build' is not supported for docker backend")
            installation = be.rpm_install(img_obj, self.name)

        install_args = img_obj.get_label('INSTALL')

        if installation or install_args:
            try:
                name = img_obj.fq_name
            except RegistryInspectError:
                name = img_obj.input_name
            install_data_content = {
                'id': img_obj.id,
                "container_name": self.name,
                'install_date': strftime("%Y-%m-%d %H:%M:%S", gmtime())
            }
            if installation:
                # let's fail the installation if rpm for this image is already installed
                if util.InstallData.image_installed(img_obj):
                    raise ValueError("Image {} is already installed.".format(self.image))
                install_data_content["rpm_installed_files"] = installation.installed_files
                rpm_nvra = re.sub(r"\.rpm$", "", installation.original_rpm_name)
                install_data_content["system_package_nvra"] = rpm_nvra
            install_data = {name: install_data_content}

        if not install_args:
            return 0
        install_args = install_args.split()
        cmd = self.sub_env_strings(self.gen_cmd(install_args + self.quote(self.args.args)))
        self.display(cmd)

        if not self.args.display:
            result = util.check_call(cmd)
            if result == 0:
                if installation or install_args:
                    # Only write the install data if the installation worked.
                    util.InstallData.write_install_data(install_data)
            return result



    @staticmethod
    def print_install():
        return "%s %s %s" % (util.default_docker(), " ".join(INSTALL_ARGS), "/usr/bin/INSTALLCMD")

    @staticmethod
    def ostree_uri(image_name):
        for i in ['dockertar:', 'ostree:', 'docker:']:
            if image_name.startswith(i):
                return True
        return False
