"""UnboundLocalError cases"""

import re

from ..my_gettext import current_lang
from .. import info_variables
from .. import debug_helper


def get_cause(value, frame, tb_data):
    try:
        return _get_cause(value, frame, tb_data)
    except Exception as e:
        debug_helper.log_error(e)
        return None, None


def _get_cause(value, frame, tb_data):
    _ = current_lang.translate
    hint = None
    cause = _(
        "No information is known about this exception.\n"
        "Please report this example to\n"
        "https://github.com/aroberge/friendly-traceback/issues\n"
    )

    pattern = re.compile(r"local variable '(.*)' referenced before assignment")
    match = re.search(pattern, str(value))
    if match:
        cause, hint = local_variable_referenced(match.group(1), frame)

    return cause, hint


def local_variable_referenced(unknown_name, frame):
    _ = current_lang.translate
    cause = hint = None
    scopes = info_variables.get_definition_scope(unknown_name, frame)
    if not scopes:
        similar = info_variables.get_similar_names(unknown_name, frame)
        if similar["best"] is not None:
            best_guess = similar["best"]
            if best_guess in similar["locals"]:
                hint = _("Did you mean `{name}`?\n").format(name=similar["best"])
                cause = format_similar_names(unknown_name, similar)
                return cause, hint

        else:
            cause = info_variables.name_has_type_hint(unknown_name, frame)
            if cause:
                hint = _("Did you use a colon instead of an equal sign?\n")
        return cause, hint

    if "global" in scopes and "nonlocal" in scopes:
        cause = _(
            "The name `{var_name}` exists in both the global and nonlocal scope.\n"
            "This can be rather confusing and is not recommended.\n"
            "Depending on which variable you wanted to refer to, you needed to add either\n\n"
            "    global {var_name}\n\n"
            "or\n\n"
            "    nonlocal {var_name}\n\n"
            "as the first line inside your function.\n"
        ).format(var_name=unknown_name)
        hint = _(
            "Did you forget to add either `global {var_name}` or \n"
            "`nonlocal {var_name}`?\n"
        ).format(var_name=unknown_name)
        return cause, hint

    if "global" in scopes:
        scope = "global"
    elif "nonlocal" in scopes:
        scope = "nonlocal"
    else:
        return cause, hint

    cause = _(
        "The name `{var_name}` exists in the {scope} scope.\n"
        "Perhaps the statement\n\n"
        "    {scope} {var_name}\n\n"
        "should have been included as the first line inside your function.\n"
    ).format(var_name=unknown_name, scope=scope)

    hint = _("Did you forget to add `{scope} {var_name}`?\n").format(
        var_name=unknown_name, scope=scope
    )

    return cause, hint


def format_similar_names(unknown_name, similar):
    """This function formats the names that were found to be similar"""
    _ = current_lang.translate

    nb_similar_names = len(similar["locals"])
    if nb_similar_names == 1:
        return (
            _("The similar name `{name}` was found in the local scope. ").format(
                name=str(similar["locals"][0]).replace("'", "")
            )
            + "\n"
        )

    message = _(
        "Instead of writing `{name}`, perhaps you meant one of the following:\n"
    ).format(name=unknown_name)
    message += (
        _("*   Local scope: ") + str(similar["locals"])[1:-1].replace("'", "`") + "\n"
    )

    return message
