"""Authorization gating and login-lockout tests.

Covers the security fixes:
  - write routes require a permission/role, not just authentication
  - the admin role bypasses permission checks
  - repeated bad logins lock the account
"""


def test_member_cannot_write_settings(client, db, member_headers):
    """An authenticated user with no roles is forbidden from editing settings."""
    from shopdb.core.models import Setting

    setting = Setting(key='zabbix_enabled', value='false', valuetype='boolean',
                      category='integrations')
    db.session.add(setting)
    db.session.commit()

    response = client.put('/api/settings/zabbix_enabled',
                          json={'value': True}, headers=member_headers)
    assert response.status_code == 403
    assert response.get_json()['data']['error']['code'] == 'FORBIDDEN'


def test_admin_can_write_settings(client, db, auth_headers):
    """The admin role bypasses the permission check and may edit settings."""
    from shopdb.core.models import Setting

    setting = Setting(key='zabbix_enabled', value='false', valuetype='boolean',
                      category='integrations')
    db.session.add(setting)
    db.session.commit()

    response = client.put('/api/settings/zabbix_enabled',
                          json={'value': True}, headers=auth_headers)
    assert response.status_code == 200


def test_member_cannot_delete_asset(client, db, member_headers):
    """A role-less user cannot delete assets (was previously allowed)."""
    response = client.delete('/api/assets/1', headers=member_headers)
    # Forbidden by authz, not a 404 - the gate runs before the lookup.
    assert response.status_code == 403


def test_unauthenticated_write_is_rejected(client, db):
    """No token at all still cannot reach a write route."""
    response = client.delete('/api/assets/1')
    assert response.status_code in (401, 422)  # missing/!invalid JWT


def test_member_cannot_create_business_unit(client, db, member_headers):
    """Reference-data writes are admin-only."""
    response = client.post('/api/businessunits',
                           json={'businessunit': 'Test BU'}, headers=member_headers)
    assert response.status_code == 403


def test_account_locks_after_repeated_bad_logins(client, db, admin_user):
    """Five bad passwords lock the account; a correct password is then refused."""
    for _ in range(5):
        bad = client.post('/api/auth/login',
                          json={'username': 'testadmin', 'password': 'wrong'})
        assert bad.status_code == 401

    # Account is now locked - even the correct password is refused with 403.
    locked = client.post('/api/auth/login',
                         json={'username': 'testadmin', 'password': 'testpass'})
    assert locked.status_code == 403
    assert 'locked' in locked.get_json()['data']['error']['message'].lower()


def test_successful_login_resets_failed_counter(client, db, admin_user):
    """A good login before the threshold clears the failure count."""
    for _ in range(3):
        client.post('/api/auth/login',
                    json={'username': 'testadmin', 'password': 'wrong'})

    ok = client.post('/api/auth/login',
                     json={'username': 'testadmin', 'password': 'testpass'})
    assert ok.status_code == 200

    from shopdb.core.models import User
    user = User.query.filter_by(username='testadmin').first()
    assert user.failedlogins == 0
    assert user.lockeduntil is None
