"""Tests for the printer installer endpoint (/api/printers/install-list).

The signed printer installer EXE pulls network-printer data + floor-map
positions from here (shopfloor 2.0 cannot run unsigned .bat maps).
"""

import pytest


@pytest.fixture
def printer_assettype(db):
    from shopdb.core.models import AssetType
    at = AssetType(assettype='printer', pluginname='printers',
                   tablename='printers', description='Printers')
    db.session.add(at)
    db.session.commit()
    return at


def test_install_list_returns_network_printer_with_map(client, db, auth_headers,
                                                       printer_assettype):
    """A network printer appears with flat installer fields incl map position."""
    created = client.post('/api/printers', json={
        'assetnumber': 'CSF01-Materials-HP',
        'hostname': 'wjprn01',
        'installpath': r'\\srv\drivers\hp',
        'mapx': 120, 'mapy': 240,
    }, headers=auth_headers)
    assert created.status_code == 201, created.get_json()

    resp = client.get('/api/printers/install-list', headers=auth_headers)
    assert resp.status_code == 200
    rows = resp.get_json()['data']
    row = next((r for r in rows if r['machinenumber'] == 'CSF01-Materials-HP'), None)
    assert row is not None
    assert row['hostname'] == 'wjprn01'
    assert row['installpath'] == r'\\srv\drivers\hp'
    assert row['mapx'] == 120 and row['mapy'] == 240


def test_install_list_vendorname_resolves_via_model(client, db, auth_headers,
                                                    printer_assettype):
    """vendorname falls back to the model's vendor when the printer has no
    direct vendorid (the import sets the model, not the printer's vendor). The
    Inno installer filters on this, so it must not be null on real data."""
    from shopdb.core.models import Vendor, Model

    hp = Vendor(vendor='HP')
    db.session.add(hp)
    db.session.commit()
    model = Model(modelnumber='LaserJet M607', vendorid=hp.vendorid)
    db.session.add(model)
    db.session.commit()

    client.post('/api/printers', json={
        'assetnumber': 'CSF09-2022-HP', 'hostname': 'wjprn09',
        'modelnumberid': model.modelnumberid,
    }, headers=auth_headers)

    resp = client.get('/api/printers/install-list', headers=auth_headers)
    row = next((r for r in resp.get_json()['data']
                if r['machinenumber'] == 'CSF09-2022-HP'), None)
    assert row is not None
    assert row['vendorname'] == 'HP'


def test_install_list_text_format(client, db, auth_headers, printer_assettype):
    """format=text returns one pipe-delimited line per printer (fixed field
    order) so the Inno installers split() instead of parsing JSON.

    FIELD ORDER 0..7 IS FROZEN. The shipped installer reads them by index
    (`GetField(Line, 6)` for mapx), so a field inserted anywhere but the end
    silently shifts every later one: the installer would read a model number as
    a coordinate and still run. levelid is appended as field 8, which installers
    built before levels existed simply never read.
    """
    client.post('/api/printers', json={
        'assetnumber': 'CSF01-HP', 'windowsname': 'CSF01-HP', 'hostname': 'wjprn01',
        'mapx': 120, 'mapy': 240,
    }, headers=auth_headers)

    resp = client.get('/api/printers/install-list?format=text', headers=auth_headers)
    assert resp.status_code == 200
    assert resp.mimetype == 'text/plain'
    line = next((l for l in resp.get_data(as_text=True).splitlines()
                 if 'CSF01-HP' in l), None)
    assert line is not None
    cols = line.split('|')
    # printerid|windowsname|vendorname|modelnumber|hostname|ipaddress|mapx|mapy
    # |levelid
    assert len(cols) == 9
    assert cols[1] == 'CSF01-HP'      # windowsname (falls back to assetnumber name)
    assert cols[4] == 'wjprn01'       # hostname
    assert cols[6] == '120' and cols[7] == '240'
    # levelid last, and empty rather than absent when the printer has no level:
    # the field count must not vary between rows or a positional split breaks.
    assert cols[8] == ''


def test_install_list_excludes_usb_only_printer(client, db, auth_headers,
                                                printer_assettype):
    """A printer with no hostname and no network IP is excluded."""
    client.post('/api/printers', json={'assetnumber': 'USB-LABELER'},
                headers=auth_headers)
    resp = client.get('/api/printers/install-list', headers=auth_headers)
    machinenumbers = [r['machinenumber'] for r in resp.get_json()['data']]
    assert 'USB-LABELER' not in machinenumbers
