"""
Init flow based helper functions
"""
import functools
import logging
import re

from samcli.lib.utils.architecture import X86_64
from samcli.local.common.runtime_template import INIT_RUNTIMES, LAMBDA_IMAGES_RUNTIMES_MAP, is_custom_runtime

LOG = logging.getLogger(__name__)


def get_sorted_runtimes(runtime_option_list):
    """
    Return a list of sorted runtimes in ascending order of runtime names and
    descending order of runtime version.

    Parameters
    ----------
    runtime_option_list : list
        list of possible runtime to be selected

    Returns
    -------
    list
        sorted list of possible runtime to be selected
    """
    supported_runtime_list = get_supported_runtime(runtime_option_list)
    return sorted(supported_runtime_list, key=functools.cmp_to_key(compare_runtimes))


def get_supported_runtime(runtime_list):
    """
    Returns a list of only runtimes supported by the current version of SAMCLI.
    This is the list that is presented to the customer to select from.

    Parameters
    ----------
    runtime_list : list
        List of runtime

    Returns
    -------
    list
        List of supported runtime
    """
    supported_runtime_list = []
    error_message = ""
    for runtime in runtime_list:
        if runtime not in INIT_RUNTIMES and not is_custom_runtime(runtime):
            if not error_message:
                error_message = "Additional runtimes may be available in the latest SAM CLI version. \
                    Upgrade your SAM CLI to see the full list."
                LOG.debug(error_message)
            continue
        supported_runtime_list.append(runtime)

    return supported_runtime_list


def compare_runtimes(first_runtime, second_runtime):
    """
    Logic to compare supported runtime for sorting.

    Parameters
    ----------
    first_runtime : str
        runtime to be compared
    second_runtime : str
        runtime to be compared

    Returns
    -------
    int
        comparison result
    """

    first_runtime_name, first_version_number = _split_runtime(first_runtime)
    second_runtime_name, second_version_number = _split_runtime(second_runtime)

    if first_runtime_name == second_runtime_name:
        if first_version_number == second_version_number:
            # If it's the same runtime and version return al2 first
            return -1 if first_runtime.endswith(".al2") else 1
        return second_version_number - first_version_number

    return 1 if first_runtime_name > second_runtime_name else -1


def _split_runtime(runtime):
    """
    Split a runtime into its name and version number.

    Parameters
    ----------
    runtime : str
        Runtime in the format supported by Lambda

    Returns
    -------
    (str, float)
        Tuple of runtime name and runtime version
    """
    return (_get_runtime_name(runtime), _get_version_number(runtime))


def _get_runtime_name(runtime):
    """
    Return the runtime name without the version

    Parameters
    ----------
    runtime : str
        Runtime in the format supported by Lambda.

    Returns
    -------
    str
        Runtime name, which is obtained as everything before the first number
    """
    return re.split(r"\d", runtime)[0]


def _get_version_number(runtime):
    """
    Return the runtime version number

    Parameters
    ----------
    runtime_version : str
        version of a runtime

    Returns
    -------
    float
        Runtime version number
    """

    if is_custom_runtime(runtime):
        return 1.0
    return float(re.search(r"\d+(\.\d+)?", runtime).group())


def _get_templates_with_dependency_manager(templates_options, dependency_manager):
    return [t for t in templates_options if t.get("dependencyManager") == dependency_manager]


def _get_runtime_from_image(image):
    """
    Get corresponding runtime from the base-image parameter
    """
    runtime = image[image.find("/") + 1 : image.find("-")]
    return runtime


def _get_image_from_runtime(runtime):
    """
    Get corresponding base-image from the runtime parameter
    """
    return LAMBDA_IMAGES_RUNTIMES_MAP[runtime]


def get_architectures(architecture):
    """
    Returns list of architecture value based on the init input value
    """
    return [X86_64] if architecture is None else [architecture]
