"""The collector reporter, generated with a site's own values.

A site used to receive a script with the reference site's server and VLANs in
it, which it had to find and edit. The server now stamps its own values into the
parameter defaults, so the file downloads ready to deploy.

What must stay true:

- ONLY the defaults are substituted. The copy in the repo stays runnable, so
  there is never a second version to drift from the first.
- The collector key is NEVER in the file. It lands on every shop-floor PC, and a
  token spread across hundreds of bays cannot be rotated quietly.
- Everything stamped is still overridable, because a bay may need to differ from
  its site.
"""

import pytest

from shopdb.core.models import Setting


SCRIPT = '/api/computers/client-script'


def _set(db, key, value):
    row = Setting.query.filter_by(key=key).first()
    if row is None:
        row = Setting(key=key, value=value, valuetype='string', category='computers')
        db.session.add(row)
    else:
        row.value = value
    db.session.commit()


def test_an_anonymous_caller_gets_nothing(client):
    """It states a site's URL and internal ranges - configuration, not a
    handout."""
    assert client.get(SCRIPT).status_code in (401, 422)


def test_it_serves_the_reporter_as_a_download(client, auth_headers):
    resp = client.get(SCRIPT, headers=auth_headers)
    assert resp.status_code == 200, resp.get_data(as_text=True)[:200]
    assert 'attachment' in resp.headers['Content-Disposition']
    assert 'Report-AssetToShopDB.ps1' in resp.headers['Content-Disposition']
    body = resp.get_data(as_text=True)
    assert 'param(' in body
    assert 'api/collector/computers' in body


def test_it_publishes_a_hash_of_what_it_served(client, auth_headers):
    """So a deployment can verify what it fetched, like the installer does."""
    import hashlib
    resp = client.get(SCRIPT, headers=auth_headers)
    digest = hashlib.sha256(resp.get_data()).hexdigest()
    assert resp.headers['X-Script-Sha256'] == digest


def test_it_stamps_the_sites_own_url(client, db, auth_headers):
    _set(db, 'site_base_url', 'https://shopdb.example.net')
    body = client.get(SCRIPT, headers=auth_headers).get_data(as_text=True)
    assert "[string]$ApiUrl = 'https://shopdb.example.net/api/collector/computers'" in body
    assert 'for https://shopdb.example.net' in body


def test_a_site_with_no_url_configured_still_gets_a_usable_script(client, db,
                                                                  auth_headers):
    """Blank site_base_url falls back to the origin the admin is talking to,
    which is by definition a reachable address for this server."""
    _set(db, 'site_base_url', '')
    body = client.get(SCRIPT, headers=auth_headers).get_data(as_text=True)
    assert "[string]$ApiUrl = ''" not in body
    assert 'api/collector/computers' in body


def test_it_stamps_the_sites_ranges(client, db, auth_headers):
    """The replacement for the two VLANs that used to be source code."""
    _set(db, 'computers_routableranges', '10.20.0.0/23,10.21.4.0/26')
    body = client.get(SCRIPT, headers=auth_headers).get_data(as_text=True)
    assert "[string]$AllowedRanges = '10.20.0.0/23,10.21.4.0/26'" in body


def test_no_ranges_configured_leaves_the_default_route_fallback(client, db,
                                                               auth_headers):
    """An unconfigured site must not be given someone else's addressing: the
    script falls back to the NIC carrying the default route."""
    _set(db, 'computers_routableranges', '')
    body = client.get(SCRIPT, headers=auth_headers).get_data(as_text=True)
    assert "[string]$AllowedRanges = ''" in body
    assert 'default route' in body


def test_the_collector_key_is_never_in_the_file(client, db, auth_headers):
    """The one thing that must not be stamped in. A token in a file on every bay
    is a token nobody can rotate quietly."""
    _set(db, 'site_base_url', 'https://shopdb.example.net')
    body = client.get(SCRIPT, headers=auth_headers).get_data(as_text=True)
    assert 'shopdb_pat_' not in body
    assert "$ApiKey = ''" in body or "[string]$ApiKey = ''" in body
    # It says where the key comes from instead.
    assert 'CollectorKey' in body


def test_the_body_is_not_rewritten_only_the_defaults(client, auth_headers):
    """The repo copy stays runnable. If generation started editing the body,
    the file on disk and the file a site runs would diverge."""
    from plugins.computers.api.routes import _client_script_path
    with open(_client_script_path(), 'r', encoding='utf-8') as handle:
        source = handle.read()
    body = client.get(SCRIPT, headers=auth_headers).get_data(as_text=True)

    # Every line of the source survives except the two parameter defaults.
    changed = [line for line in source.splitlines()
               if line.strip() and line not in body.splitlines()]
    assert all('$ApiUrl' in line or '$AllowedRanges' in line for line in changed), changed


def test_it_names_the_version_that_generated_it(client, auth_headers):
    """So a script found on a bay can be traced to the server that made it."""
    from shopdb import __version__
    body = client.get(SCRIPT, headers=auth_headers).get_data(as_text=True)
    assert __version__ in body
