"""Generate a network device's asset number from its type prefix and name.

Every network device on this fleet already follows one convention, applied by
hand: AP-<name>, SW-<name>, SVR-<name>, IDF-<name>. This turns that into
something the create path does, so the same value is not typed twice.

Generation only fills a BLANK asset number. A device that carries a real
identifier of its own - a vendor tag, a controller name, a serial - keeps it.
That is the platform rule: adopt an external identifier where one exists, derive
one only where none does.
"""

import re


# Characters that must not reach a unique business key. assetnumber ends up in
# URLs and in joins other subsystems make, and the existing data already shows
# why this matters: IDF-Telco-Demarc-#1 came from the name 'Telco Demarc #1',
# carrying a '#' into an identifier.
_SEPARATORS = re.compile(r'[\s_/\\]+')
_ILLEGAL = re.compile(r'[^A-Za-z0-9.-]')
_RUNS = re.compile(r'-{2,}')


def sanitize(value):
    """A name reduced to something safe to use as an identifier.

    Whitespace and slashes become single dashes; anything outside
    letters/digits/dot/dash is dropped rather than transliterated, because a
    guessed transliteration in a business key is worse than a shorter one.
    """
    text = (value or '').strip()
    if not text:
        return ''
    text = _SEPARATORS.sub('-', text)
    text = _ILLEGAL.sub('', text)
    text = _RUNS.sub('-', text)
    return text.strip('-')


def generate(prefix, name):
    """'<PREFIX>-<name>', or the bare name when the type has no prefix.

    Returns '' when there is nothing to build from, so the caller can fall back
    to demanding an explicit value rather than inventing one.

    Does NOT stack an existing prefix: a name already starting with the prefix
    (IDF-03 under type IDF) is returned as-is, because IDF-IDF-03 is nobody's
    intent. Matched case-insensitively on the prefix plus its dash.
    """
    cleanname = sanitize(name)
    if not cleanname:
        return ''
    cleanprefix = sanitize(prefix).upper()
    if not cleanprefix:
        return cleanname
    if cleanname.upper().startswith(cleanprefix + '-'):
        return cleanname
    return '{}-{}'.format(cleanprefix, cleanname)


def generate_for_type(networkdevicetypeid, name):
    """Same, looking the prefix up from the device type. '' if no type given."""
    if not networkdevicetypeid:
        return sanitize(name)
    from shopdb.api import db
    from ..models import NetworkDeviceType

    devicetype = db.session.get(NetworkDeviceType, networkdevicetypeid)
    return generate(devicetype.prefix if devicetype else None, name)
