"""A part-marker PC keeps reporting after the first cycle.

Both links a part-marker PC produces are rows in assetrelationships, which is
unique on (source, target, type). Both were looked up by LABEL, so a row made by
hand or by the legacy import was invisible and the insert violated the
constraint; and the minted marker's asset number is derived from the PC, so it
could already be taken. Either way the PC reported 200 on the cycle that minted
the marker and 500 on every cycle after - the same shape as the CMM adoption bug
in test_collector_measuringtool_adoption.py.
"""

import pytest

from shopdb.core.models import Asset, AssetType
from shopdb.core.models.relationship import RelationshipType, AssetRelationship

KEY = 'partmarker-links-key'


@pytest.fixture
def collector_key(app):
    old = app.config.get('COLLECTOR_API_KEY')
    app.config['COLLECTOR_API_KEY'] = KEY
    yield KEY
    app.config['COLLECTOR_API_KEY'] = old


@pytest.fixture
def rig(db):
    for name in ('computer', 'machine'):
        if not AssetType.query.filter_by(assettype=name).first():
            db.session.add(AssetType(assettype=name))
    for name in ('controls', 'partof'):
        if not RelationshipType.query.filter_by(relationshiptype=name).first():
            db.session.add(RelationshipType(relationshiptype=name))
    db.session.commit()


def _report(client, key, hostname, **extra):
    payload = {'hostname': hostname, 'pctype': 'gea-shopfloor-partmarker'}
    payload.update(extra)
    return client.post('/api/collector/computers', json=payload,
                       headers={'X-API-Key': key})


def _operation(db, assetnumber):
    machinetype = AssetType.query.filter_by(assettype='machine').first()
    asset = Asset(assetnumber=assetnumber, assettypeid=machinetype.assettypeid)
    db.session.add(asset)
    db.session.commit()
    return asset


def test_repeat_cycles_do_not_500(client, db, rig, collector_key):
    _operation(db, '0613')
    codes = [_report(client, collector_key, 'FMARK001', machinenumber='0613').status_code
             for _ in range(3)]
    assert codes == [codes[0]] * 3, codes
    assert codes[0] in (200, 201), codes


def test_a_partof_row_under_another_label_is_not_duplicated(
        client, db, rig, collector_key):
    """A partof row made by hand or by the legacy import carries no label."""
    operation = _operation(db, '0615')
    # First cycle mints the marker and links it.
    assert _report(client, collector_key, 'FMARK002',
                   machinenumber='0615').status_code in (200, 201)
    marker = Asset.query.filter_by(assetnumber='FMARK002-PARTMARKER').first()
    assert marker is not None
    partof = RelationshipType.query.filter_by(relationshiptype='partof').first()
    row = AssetRelationship.query.filter_by(
        sourceassetid=marker.assetid, targetassetid=operation.assetid,
        relationshiptypeid=partof.relationshiptypeid).first()
    assert row is not None
    # Somebody relabels it (or it came from the import unlabelled).
    row.label = None
    db.session.commit()

    resp = _report(client, collector_key, 'FMARK002', machinenumber='0615')
    assert resp.status_code in (200, 201), resp.status_code
    rows = AssetRelationship.query.filter_by(
        sourceassetid=marker.assetid, targetassetid=operation.assetid,
        relationshiptypeid=partof.relationshiptypeid).all()
    assert len(rows) == 1


def test_a_taken_marker_asset_number_does_not_500(client, db, rig, collector_key):
    """The minted number is derived from the PC, so it can already exist."""
    machinetype = AssetType.query.filter_by(assettype='machine').first()
    db.session.add(Asset(assetnumber='FMARK003-PARTMARKER',
                         assettypeid=machinetype.assettypeid))
    db.session.commit()
    _operation(db, '0617')

    resp = _report(client, collector_key, 'FMARK003', machinenumber='0617')
    assert resp.status_code in (200, 201), resp.status_code
