import re
from typing import Optional

REGEX_TRAILING_WHITESPACE_SINGLELINE = re.compile(r"\s{2,}")
REGEX_TRAILING_WHITESPACE_MULTILINE = re.compile(r" +\n")


def get_lines_count(string):
    # TODO: Windows strings
    count = string.count("\n")
    if string[-1] != "\n":
        count += 1
    return count


# https://gist.github.com/bgusach/a967e0587d6e01e889fd1d776c5f3729
# https://stackoverflow.com/a/6117124/598057
def multireplace(string, replacements):
    # Place longer ones first to keep shorter substrings from matching where the
    # longer ones should take place. For instance, given the replacements:
    # {'ab': 'AB', 'abc': 'ABC'} against the string 'hey abc', it should produce
    # 'hey ABC' and not 'hey ABc'
    rep_sorted = sorted(replacements, key=len, reverse=True)
    rep_escaped = map(re.escape, rep_sorted)

    pattern = re.compile("|".join(rep_escaped), 0)
    return pattern.sub(lambda match: replacements[match.group(0)], string)


# WIP: Check if this is used.
def escape(string: str) -> str:
    return string.encode("unicode_escape").decode("utf-8")


# WIP: Check if this is used.
def unescape(string: str) -> str:
    return string.encode("utf-8").decode("unicode_escape")


def sanitize_html_form_field(field: str, multiline: bool) -> str:
    assert isinstance(field, str)
    if len(field) > 0:
        sanitized_field: str = field.strip()
        if len(sanitized_field) > 0:
            if multiline:
                return REGEX_TRAILING_WHITESPACE_MULTILINE.sub(
                    "\n", sanitized_field
                )
            sanitized_field = sanitized_field.replace("\r\n", "")
            return REGEX_TRAILING_WHITESPACE_SINGLELINE.sub(
                " ", sanitized_field
            )
    return ""


def is_uppercase_underscore_string(string: str) -> bool:
    first_word = r"[A-Z][A-Z0-9]*"
    other_word = r"[A-Z0-9]+"
    pattern = re.compile(rf"^{first_word}(_{other_word})*$")
    return pattern.match(string) is not None


def is_safe_alphanumeric_string(string: str) -> bool:
    pattern = re.compile(r"^[\w.]+([/\\][\w.]+?)*$")
    return pattern.match(string) is not None


def create_safe_acronym(string: str) -> str:
    words = re.split(r"[\W+]", string)
    acronym = ""
    for word in words:
        if len(word) == 0:
            continue
        if word[0].isalpha():
            acronym += word[0].upper()
    return acronym


def create_safe_title_string(string):
    return re.sub(r"[^\w0-9]+", "-", string).rstrip("-")


def extract_last_numeric_part(string: str) -> str:
    regex_match = re.match(".*?([0-9]+)$", string)
    if regex_match is not None:
        return regex_match.group(1)
    raise ValueError(f"Cannot extract the numeric part of UID: {string}")


def extract_numeric_uid_prefix_part(string: str) -> Optional[str]:
    regex_match = re.match(r"^([A-Za-z].*?\D)[0-9]+$", string)
    if regex_match is not None:
        return regex_match.group(1)
    return None
