"""Asset numbers generated from the device type's prefix.

Every network device on this fleet already followed one convention applied by
hand - AP-<name>, SW-<name>, SVR-<name>, IDF-<name>, 45 records, no exceptions.
Generation codifies it so the same value is not typed twice, and must reproduce
those records exactly rather than inventing a new scheme.
"""

import pytest

from shopdb.extensions import db
from shopdb.core.models import AssetType
from plugins.network.models import NetworkDeviceType


def _devicetype(db, name, prefix):
    """A device type, with the core asset type the create path needs present."""
    if not AssetType.query.filter_by(assettype='network_device').first():
        db.session.add(AssetType(assettype='network_device'))
    devicetype = NetworkDeviceType(networkdevicetype=name, prefix=prefix)
    db.session.add(devicetype)
    db.session.commit()
    return devicetype
from plugins.network.services.assetnumbers import generate, sanitize


@pytest.mark.parametrize('prefix,name,expected', [
    ('AP', 'AIRwdMUSwestj02', 'AP-AIRwdMUSwestj02'),
    ('SW', 'AIRsdMUSwestj01', 'SW-AIRsdMUSwestj01'),
    ('SVR', 'AVEWP4546V01', 'SVR-AVEWP4546V01'),
])
def test_reproduces_the_existing_convention(prefix, name, expected):
    assert generate(prefix, name) == expected


def test_a_type_with_no_prefix_gives_the_bare_name():
    """Nullable on purpose - nobody invents a prefix for a type that wants none."""
    assert generate(None, 'Bare Name') == 'Bare-Name'
    assert generate('', 'Bare Name') == 'Bare-Name'


def test_an_already_prefixed_name_is_not_stacked():
    """IDF-03 under type IDF is IDF-03, never IDF-IDF-03. Real row on this data."""
    assert generate('IDF', 'IDF-03') == 'IDF-03'
    assert generate('idf', 'idf-03') == 'idf-03'


def test_characters_that_break_a_business_key_are_stripped():
    """assetnumber lands in URLs and in joins. The existing IDF-Telco-Demarc-#1
    row shows a '#' reaching a unique key, which is what this prevents."""
    assert generate('IDF', 'Telco Demarc #1') == 'IDF-Telco-Demarc-1'
    assert generate('APNL', 'Door 4 / West') == 'APNL-Door-4-West'
    assert sanitize('  spaced  out  ') == 'spaced-out'


def test_nothing_to_build_from_returns_empty():
    """So the caller demands an explicit value instead of inventing one."""
    assert generate('AP', '') == ''
    assert generate('AP', None) == ''


def test_create_generates_when_assetnumber_is_blank(client, db, auth_headers):
    devicetype = _devicetype(db, 'Access Panel', 'APNL')

    resp = client.post('/api/network', json={
        'name': 'Dock Door 4',
        'networkdevicetypeid': devicetype.networkdevicetypeid,
    }, headers=auth_headers)
    assert resp.status_code == 201, resp.get_json()
    assert resp.get_json()['data']['assetnumber'] == 'APNL-Dock-Door-4'


def test_an_explicit_assetnumber_always_wins(client, db, auth_headers):
    """Adopt an external identifier where one exists - a vendor tag beats a
    generated value, which is why generation only fills a BLANK field."""
    devicetype = _devicetype(db, 'Access Panel 2', 'APNL')

    resp = client.post('/api/network', json={
        'assetnumber': 'VENDORTAG-99',
        'name': 'Dock Door 5',
        'networkdevicetypeid': devicetype.networkdevicetypeid,
    }, headers=auth_headers)
    assert resp.status_code == 201, resp.get_json()
    assert resp.get_json()['data']['assetnumber'] == 'VENDORTAG-99'


def test_no_name_and_no_assetnumber_is_refused(client, db, auth_headers):
    devicetype = _devicetype(db, 'Access Panel 3', 'APNL')

    resp = client.post('/api/network', json={
        'networkdevicetypeid': devicetype.networkdevicetypeid,
    }, headers=auth_headers)
    assert resp.status_code == 400
    assert 'assetnumber is required' in resp.get_json()['data']['error']['message']


def test_prefix_round_trips_through_the_type_api(client, db, auth_headers):
    created = client.post('/api/network/types', json={
        'networkdevicetype': 'Door Controller', 'prefix': 'DOOR',
    }, headers=auth_headers)
    assert created.status_code == 201, created.get_json()
    assert created.get_json()['data']['prefix'] == 'DOOR'

    typeid = created.get_json()['data']['networkdevicetypeid']
    updated = client.put(f'/api/network/types/{typeid}', json={'prefix': 'DR'},
                         headers=auth_headers)
    assert updated.status_code == 200, updated.get_json()
    assert updated.get_json()['data']['prefix'] == 'DR'
