"""Every asset list searches the type (and vendor/model) columns it displays.

Each list shows a Type column, and printers/network also show Model/Vendor, but
the search filters only looked at the asset fields - so searching 'Standard' on
PCs or 'Thermal' on printers returned nothing. One test per list, each also
proving the outer joins did not turn into inner joins.
"""

from shopdb.extensions import db as _db
from shopdb.core.models import Asset, AssetType
from shopdb.core.models.model import Model
from shopdb.core.models.vendor import Vendor

from plugins.computers.models import Computer, ComputerType
from plugins.printers.models import Printer, PrinterType
from plugins.network.models import NetworkDevice, NetworkDeviceType
from plugins.measuringtools.models import MeasuringTool, MeasuringToolType


def _assettype(name):
    assettype = AssetType(assettype=name)
    _db.session.add(assettype)
    _db.session.flush()
    return assettype


def _numbers(resp):
    return sorted(item['assetnumber'] for item in resp.get_json()['data'])


def test_pcs_search_matches_computer_type(client, db):
    assettype = _assettype('computer')
    standard = ComputerType(computertype='Standard')
    _db.session.add(standard)
    _db.session.flush()

    typed = Asset(assetnumber='PC-1', assettypeid=assettype.assettypeid)
    untyped = Asset(assetnumber='PC-2', name='spare bench box',
                    assettypeid=assettype.assettypeid)
    _db.session.add_all([typed, untyped])
    _db.session.flush()
    _db.session.add_all([
        Computer(assetid=typed.assetid, computertypeid=standard.computertypeid),
        Computer(assetid=untyped.assetid),
    ])
    _db.session.commit()

    resp = client.get('/api/computers?search=Standard')
    assert resp.status_code == 200, resp.get_json()
    assert _numbers(resp) == ['PC-1']

    # the typeless PC is still findable on its own fields
    resp = client.get('/api/computers?search=bench')
    assert _numbers(resp) == ['PC-2']


def test_printers_search_matches_type_and_model(client, db):
    assettype = _assettype('printer')
    thermal = PrinterType(printertype='Thermal')
    model = Model(modelnumber='ZT411')
    _db.session.add_all([thermal, model])
    _db.session.flush()

    labeler = Asset(assetnumber='PR-1', assettypeid=assettype.assettypeid)
    plain = Asset(assetnumber='PR-2', name='old plotter',
                  assettypeid=assettype.assettypeid)
    _db.session.add_all([labeler, plain])
    _db.session.flush()
    _db.session.add_all([
        Printer(assetid=labeler.assetid, printertypeid=thermal.printertypeid,
                modelnumberid=model.modelnumberid),
        Printer(assetid=plain.assetid),
    ])
    _db.session.commit()

    for term in ['Thermal', 'ZT411']:
        resp = client.get(f'/api/printers?search={term}')
        assert resp.status_code == 200, resp.get_json()
        assert _numbers(resp) == ['PR-1'], term

    resp = client.get('/api/printers?search=plotter')
    assert _numbers(resp) == ['PR-2']


def test_network_search_matches_type_and_vendor(client, db):
    assettype = _assettype('network_device')
    switchtype = NetworkDeviceType(networkdevicetype='Switch')
    vendor = Vendor(vendor='Cisco')
    _db.session.add_all([switchtype, vendor])
    _db.session.flush()

    switch = Asset(assetnumber='NET-1', assettypeid=assettype.assettypeid)
    plain = Asset(assetnumber='NET-2', name='unmanaged hub',
                  assettypeid=assettype.assettypeid)
    _db.session.add_all([switch, plain])
    _db.session.flush()
    _db.session.add_all([
        NetworkDevice(assetid=switch.assetid,
                      networkdevicetypeid=switchtype.networkdevicetypeid,
                      vendorid=vendor.vendorid),
        NetworkDevice(assetid=plain.assetid),
    ])
    _db.session.commit()

    for term in ['Switch', 'Cisco']:
        resp = client.get(f'/api/network?search={term}')
        assert resp.status_code == 200, resp.get_json()
        assert _numbers(resp) == ['NET-1'], term

    resp = client.get('/api/network?search=hub')
    assert _numbers(resp) == ['NET-2']


def test_measuringtools_search_matches_type(client, db):
    assettype = _assettype('measuring_tool')
    caliper = MeasuringToolType(name='Caliper')
    _db.session.add(caliper)
    _db.session.flush()

    typed = Asset(assetnumber='MT-1', assettypeid=assettype.assettypeid)
    untyped = Asset(assetnumber='MT-2', name='height gage',
                    assettypeid=assettype.assettypeid)
    _db.session.add_all([typed, untyped])
    _db.session.flush()
    _db.session.add_all([
        MeasuringTool(assetid=typed.assetid,
                      measuringtooltypeid=caliper.measuringtooltypeid),
        MeasuringTool(assetid=untyped.assetid),
    ])
    _db.session.commit()

    resp = client.get('/api/measuringtools?search=Caliper')
    assert resp.status_code == 200, resp.get_json()
    assert _numbers(resp) == ['MT-1']

    resp = client.get('/api/measuringtools?search=height')
    assert _numbers(resp) == ['MT-2']


def test_core_assets_search_matches_asset_type(client, db):
    """The unified asset list shows a Type column too."""
    machine_type = _assettype('machine')
    printer_type = _assettype('printer')
    _db.session.add_all([
        Asset(assetnumber='A-1', assettypeid=machine_type.assettypeid),
        Asset(assetnumber='A-2', assettypeid=printer_type.assettypeid),
    ])
    _db.session.commit()

    resp = client.get('/api/assets?search=machine')
    assert resp.status_code == 200, resp.get_json()
    assert _numbers(resp) == ['A-1']


def test_core_assets_search_type_filter_still_works(client, db):
    """The type-name filter joins AssetType; search uses EXISTS, so both apply."""
    machine_type = _assettype('machine')
    _db.session.add_all([
        Asset(assetnumber='A-1', name='mill', assettypeid=machine_type.assettypeid),
        Asset(assetnumber='A-2', name='lathe', assettypeid=machine_type.assettypeid),
    ])
    _db.session.commit()

    resp = client.get('/api/assets?type=machine&search=mill')
    assert resp.status_code == 200, resp.get_json()
    assert _numbers(resp) == ['A-1']
