# Copyright (c) 2017 VMware, Inc.  All rights reserved. -- VMware Confidential

"""
vpxd-svcs component module for B2B patching.
"""
import os
import sys
import logging
import vcsa_utils
from .constants import *
from extensions import extend, Hook
from fss_utils import getTargetFSS
from l10n import msgMetadata as _T, localizedString as _
from patch_specs import Requirements, PatchInfo, RequirementsResult
from reporting import getProgressReporter

VPXD_SVCS_PATCHES_DIR = os.path.dirname(__file__)
# Import patches directory where all patches reside.
sys.path.append(os.path.join(VPXD_SVCS_PATCHES_DIR, "patches"))

logger = logging.getLogger(__name__)
# Earlier versions of vpxd-svcs do not have the vpxdsvcs.version property in
# dataservice.proprties file. In such a case the installed_version method will
# return 0.
patches = [
    (1, "patch-01")
]


def installed_version():
    """
    Returns the vpxd-svcs version currently installed. We return 0 if there is
    no version field in the dataservice.properties file.
    """
    version = readprop(DATASERVICES_PROP, VERSION)
    if not version:
        return 0
    return int(version)


def getChangesSummary():
    curr_patch_script = patches[-1][1]
    mod = __import__(curr_patch_script)
    return mod.getChanges()


@extend(Hook.Discovery)
def discover(ctx):
    """
    DiscoveryResult discover(PatchContext sharedCtx) throw
    UserUpgradeError.
    """
    # Don't run patches if Compute Policy is not enabled on target build.
    if not getTargetFSS("ComputePolicy"):
        logger.info("Compute Policy not enabled on target build. "
                    "Patch not applicable.")
        return None

    # Not applicable if this is a N node.
    if not os.path.exists(VPXD_SVCS_CONFIG_DIR):
        logger.info("vpxd-svcs config not found. Patch not applicable.")
        return None

    return vcsa_utils.getComponentDiscoveryResult(
        "vpxd-svcs", displayName=_(_T("vpxd-svcs.displayName",
                                      "VMware vCenter-Services")))


@extend(Hook.Requirements)
def collectRequirements(ctx):
    """RequirementsResult collectRequirements(PatchContext sharedCtx)"""
    requirements = Requirements()
    mismatches = []
    patchInfo = PatchInfo(summary=getChangesSummary())
    return RequirementsResult(requirements, patchInfo, mismatches)


def _doIncrementalPatching(ctx):
    installed = installed_version()

    for ver, module_path in patches:
        if ver <= installed:
            continue
        patch_module = __import__(module_path)
        logger.info("Applying Compute Policy patch version {}".format(ver))
        patch_module.doPatching(ctx)
        logger.info("Patch %s applied" % (module_path))

    # If there was a patch installed, update the version and remove the
    # .rpmnew file.
    if os.path.exists(DATASERVICES_PROP_NEW):
        if not readprop(DATASERVICES_PROP, VERSION):
            with open(DATASERVICES_PROP, "a") as prop_file:
                prop_file.write("# vpxd-svcs version\n")
                prop_file.write("{}={}\n".format(VERSION, patches[-1][0]))
        else:
            replace_properties_in_file(DATASERVICES_PROP,
                                       {VERSION: patches[-1][0]})

        os.remove(DATASERVICES_PROP_NEW)
    else:
        logger.info("Upgrade between same versions of vpxd-svcs.")


@extend(Hook.Patch)
def patch(ctx):
    """void patch(PatchContext ctx) throw UserError"""

    # We import cis.utils in the Patch hook to ensure it is
    # patched to work with python 3.
    sys.path.append(os.environ['VMWARE_PYTHON_PATH'])
    from cis.utils import readprop, replace_properties_in_file

    progressReporter = getProgressReporter()
    progressReporter.updateProgress(0, _(_T("vpxd-svcs.patch.begin",
                                            "Start vpxd-svcs patching")))
    _doIncrementalPatching(ctx)
    progressReporter.updateProgress(100, _(_T("vpxd-svcs.patch.complete",
                                              "patching vpxd-svcs completed")))
