"""Global search matches custom-field VALUES for fields flagged searchable.

Pins: a searchable custom field's value routes to its asset; a non-searchable
field is NOT matched; disabling the asset's search domain excludes the hit; an
asset matched by BOTH its assetnumber and a custom field appears once; an
inactive field is excluded.

Search by a distinctive value string so only the custom-field domain can match
(the value is not any built-in identifier).
"""

from shopdb.core.api.settings import invalidate_settings_cache


def _seed_computer(client, db, auth_headers, assetnumber):
    """Create a computer asset and return its assetid."""
    from shopdb.core.models import AssetType, Asset
    if not AssetType.query.filter_by(assettype='computer').first():
        db.session.add(AssetType(assettype='computer', pluginname='computer',
                                 tablename='computer', description='c'))
        db.session.commit()
    resp = client.post('/api/computers',
                       json={'assetnumber': assetnumber},
                       headers=auth_headers)
    assert resp.status_code == 201, resp.get_json()
    asset = Asset.query.filter_by(assetnumber=assetnumber).first()
    return asset.assetid


def _seed_field(db, label, searchable=True, isactive=True):
    """Create a computer-scoped custom field and return its fieldid."""
    from shopdb.core.models import AssetType, CustomField
    assettype = AssetType.query.filter_by(assettype='computer').first()
    field = CustomField(assettypeid=assettype.assettypeid,
                        fieldkey=label.replace(' ', '').lower(),
                        label=label, datatype='text',
                        searchable=searchable, isactive=isactive)
    db.session.add(field)
    db.session.commit()
    return field.fieldid


def _set_value(db, fieldid, assetid, value):
    from shopdb.core.models import CustomFieldValue
    db.session.add(CustomFieldValue(fieldid=fieldid, assetid=assetid, value=value))
    db.session.commit()


def _hits(client, auth_headers, term):
    resp = client.get(f'/api/search?q={term}', headers=auth_headers)
    assert resp.status_code == 200, resp.get_json()
    return resp.get_json()['data']['results']


def test_searchable_field_value_matches_and_routes(client, db, auth_headers):
    """A searchable custom-field value matches and routes to the asset page."""
    assetid = _seed_computer(client, db, auth_headers, 'AST-CF01')
    fieldid = _seed_field(db, 'Tool Crib Number', searchable=True)
    _set_value(db, fieldid, assetid, 'cribval01')

    hits = [r for r in _hits(client, auth_headers, 'cribval01')
            if r['type'] == 'computer']
    assert len(hits) == 1
    assert hits[0]['url'].startswith('/pcs/')
    assert hits[0]['subtitle'] == 'Tool Crib Number'


def test_non_searchable_field_value_does_not_match(client, db, auth_headers):
    """A value on a NON-searchable field is not matched by global search."""
    assetid = _seed_computer(client, db, auth_headers, 'AST-CF02')
    fieldid = _seed_field(db, 'Internal Note', searchable=False)
    _set_value(db, fieldid, assetid, 'cribval02')

    assert _hits(client, auth_headers, 'cribval02') == []


def test_disabled_domain_excludes_customfield_hit(client, db, auth_headers):
    """search_computer_enabled=false hides a custom-field hit on a computer."""
    from shopdb.core.models import Setting
    assetid = _seed_computer(client, db, auth_headers, 'AST-CF03')
    fieldid = _seed_field(db, 'Bench Tag', searchable=True)
    _set_value(db, fieldid, assetid, 'cribval03')

    # Sanity: enabled by default.
    assert [r for r in _hits(client, auth_headers, 'cribval03')
            if r['type'] == 'computer']

    Setting.set('search_computer_enabled', False, valuetype='boolean',
                category='search')
    invalidate_settings_cache()
    assert [r for r in _hits(client, auth_headers, 'cribval03')
            if r['type'] == 'computer'] == []


def test_dedupe_assetnumber_and_customfield(client, db, auth_headers):
    """An asset matched by both assetnumber and a custom field appears once."""
    assetid = _seed_computer(client, db, auth_headers, 'cribval04')
    fieldid = _seed_field(db, 'Crib Ref', searchable=True)
    _set_value(db, fieldid, assetid, 'cribval04')

    hits = [r for r in _hits(client, auth_headers, 'cribval04')
            if r['type'] == 'computer']
    assert len(hits) == 1
    # The higher-relevance built-in assetnumber match wins the dedupe.
    assert hits[0]['relevance'] == 100


def test_inactive_field_excluded(client, db, auth_headers):
    """A value on an inactive (searchable) field is not matched."""
    assetid = _seed_computer(client, db, auth_headers, 'AST-CF05')
    fieldid = _seed_field(db, 'Retired Tag', searchable=True, isactive=False)
    _set_value(db, fieldid, assetid, 'cribval05')

    assert _hits(client, auth_headers, 'cribval05') == []
