import base64
import hashlib
import hmac
import json

import pytest

from app.auth import _username_from_cookie, authenticate
from app.config import settings


def _b64url(raw: bytes) -> str:
    return base64.urlsafe_b64encode(raw).decode().rstrip("=")


def _make_jwt(payload: dict, secret: str | None = None) -> str:
    header = _b64url(json.dumps({"alg": "HS256", "typ": "JWT"}).encode())
    body = _b64url(json.dumps(payload).encode())
    signing = f"{header}.{body}".encode()
    sig = hmac.new((secret or "x").encode(), signing, hashlib.sha256).digest()
    return f"{header}.{body}.{_b64url(sig)}"


class _Headers(dict):
    """Case-insensitives .get wie Starlette-Headers (nur was wir brauchen)."""
    def get(self, key, default=None):
        return super().get(key.lower(), default)


def _cfg(monkeypatch, **over):
    monkeypatch.setattr(settings, "trusted_auth_cookie", "yunohost.portal")
    monkeypatch.setattr(settings, "trusted_auth_cookie_claim", "user")
    monkeypatch.setattr(settings, "trusted_auth_jwt_secret", over.get("secret", ""))
    return settings


def test_username_from_unsigned_cookie(monkeypatch):
    _cfg(monkeypatch)
    jwt = _make_jwt({"user": "dieterschlueter", "host": "linix.de"})
    headers = _Headers({"cookie": f"foo=bar; yunohost.portal={jwt}; baz=qux"})
    assert _username_from_cookie(headers, settings) == "dieterschlueter"


def test_no_cookie_returns_none(monkeypatch):
    _cfg(monkeypatch)
    assert _username_from_cookie(_Headers({"cookie": "foo=bar"}), settings) is None
    assert _username_from_cookie(_Headers({}), settings) is None


def test_signature_checked_when_secret_set(monkeypatch):
    _cfg(monkeypatch, secret="geheim")
    good = _make_jwt({"user": "atoor"}, secret="geheim")
    bad = _make_jwt({"user": "atoor"}, secret="falsch")
    assert _username_from_cookie(_Headers({"cookie": f"yunohost.portal={good}"}), settings) == "atoor"
    assert _username_from_cookie(_Headers({"cookie": f"yunohost.portal={bad}"}), settings) is None


def test_authenticate_via_cookie_from_trusted_proxy(monkeypatch):
    import app.dependencies as deps
    _cfg(monkeypatch)
    monkeypatch.setattr(settings, "trusted_auth_header", "")
    monkeypatch.setattr(settings, "trusted_proxy_ips", "192.168.179.10")
    monkeypatch.setattr(settings, "admin_users", "atoor,dieterschlueter,dschlueter")
    jwt = _make_jwt({"user": "dieterschlueter"})
    headers = _Headers({"cookie": f"yunohost.portal={jwt}"})

    user = authenticate(headers, "192.168.179.10", None)
    assert user is not None
    assert user.external_id == "dieterschlueter" and user.is_admin is True
    # Von fremder IP wird das Cookie ignoriert.
    assert authenticate(headers, "10.0.0.1", None) is None or \
        authenticate(headers, "10.0.0.1", None).external_id != "dieterschlueter"
