"""Sample CRM → IAM integration (spec §4/§9).

Mirrors the LMS example for the CRM application: authenticate against IAM,
validate the JWT locally, and authorize on the `customer.view` permission.

Run standalone:  python crm_example.py

Reminder: the CRM never stores passwords. It trusts IAM-issued JWTs and makes
permission-based (not role-based) authorization decisions.
"""

from __future__ import annotations

import contextlib
import os

import requests

IAM_BASE_URL = os.environ.get("IAM_BASE_URL", "http://localhost:5000")


def login(username: str, password: str) -> dict:
    """Authenticate and return the token bundle."""
    resp = requests.post(
        f"{IAM_BASE_URL}/api/auth/login",
        json={"username": username, "password": password},
        timeout=10,
    )
    resp.raise_for_status()
    return resp.json()["data"]


def verify_jwt(token: str, application: str | None = None) -> dict:
    """Validate the access token via IAM's verify endpoint — no signing key needed.

    Passing ``application`` (SIMS-186), e.g. ``"CRM"``, scopes the returned
    ``permissions`` list to just that application's codes instead of every
    application the user's roles happen to grant.
    """
    params = {"application": application} if application else None
    resp = requests.post(
        f"{IAM_BASE_URL}/api/auth/verify",
        headers={"Authorization": f"Bearer {token}"},
        params=params,
        timeout=10,
    )
    resp.raise_for_status()
    return resp.json()["data"]


def require_permission(claims: dict, permission: str) -> None:
    """Raise PermissionError unless the claim set grants `permission`."""
    if permission not in claims.get("permissions", []):
        msg = f"Missing required permission: {permission}"
        raise PermissionError(msg)


def list_customers(access_token: str) -> str:
    """Example CRM action guarded by the customer.view permission."""
    claims = verify_jwt(access_token, application="CRM")
    require_permission(claims, "customer.view")
    # The CRM would now query its own customer store, scoped by claims["scope"].
    return f"Returning customers visible to user {claims['sub']} ({claims['scope']})"


def main() -> None:
    login(os.environ["CRM_USER"],
                   os.environ["CRM_PASS"])
    with contextlib.suppress(PermissionError):
        pass


if __name__ == "__main__":
    main()
