"""Scout's View As policy and wiring over the vendored `bw_view_as` drop-in.

The drop-in owns the mechanism and the guards (server-side authorization on
start, per-request re-authorization, rank checks, nesting refusal). This module
owns only Scout's POLICY — the two hooks — plus the reporting glue.

The rule that matters everywhere else in the app: **data and permissions follow
the EFFECTIVE user; identity and audit follow the REAL one.** The identity
resolvers in `authz.py` call `verify_and_effective()` so every capability below
them is automatically the target's; the middleware blocks writes in read-only
mode so no route has to remember.
"""

import logging

from starlette.requests import Request

from app import bw_accounts as bwa
from app import bw_auth, bw_view_as
from app.config import get_settings
from app.db import SessionLocal
from app.models.account import Account
from app.services import levels

log = logging.getLogger(__name__)

ViewAsError = bw_view_as.ViewAsError

# Rank guard: a non-owner impersonator can never view a peer or better (the
# drop-in refuses equal-or-higher). Levels are DATA, so rank cannot key on
# names — a custom level would fall to zero and be refused against everyone
# (a real bug the test suite caught). Rank derives from the permissions the
# level holds; holding `scout.view_as` itself confers standing above leads and
# reviewers, which is what makes delegated View As usable at all.
_PERMISSION_WEIGHT = {
    levels.REVIEW: 1,
    levels.RESULTS_VIEW: 2,
    levels.PROJECT_MEMBERS: 2,
    levels.VIEW_AS: 3,
    levels.PROJECT_MANAGE: 4,
    levels.PROJECTS_CREATE: 4,
    levels.PROJECTS_DELETE: 4,
    "accounts.view": 4,
    "accounts.add": 4,
    "accounts.delete": 4,
    "accounts.reset_password": 4,
    "accounts.change_level": 4,
    "levels.create": 4,
    "levels.edit_permissions": 4,
    "instances.create": 4,
    "instances.grant": 4,
    "instances.default_all": 4,
    "instances.change_user_level": 4,
}
_OWNER_RANK = 1000


def can_view_as(real: str, target: str) -> bool:
    """Scout's policy: the owner always may; otherwise a level holding
    `scout.view_as` may (rank still limits who — see rank_of)."""
    return levels.is_owner(real) or levels.app_can(real, levels.VIEW_AS)


def rank_of(username: str) -> int:
    if levels.is_owner(username):
        return _OWNER_RANK
    level_name = levels.effective_level(username)
    if not level_name:
        return 0
    definition = bwa.level_def(level_name)
    if not definition:
        return 0
    held = definition["permissions"]
    return max((_PERMISSION_WEIGHT.get(p, 1) for p in held), default=0)


def target_valid(username: str) -> bool:
    """The policy above is target-existence-independent, so the drop-in needs
    this hook or a target deleted mid-session would ghost. An inactive account
    fails too — deactivating someone ends any impersonation of them on the
    next request."""
    with SessionLocal() as db:
        account = db.get(Account, (username or "").lower())
        return account is not None and account.active


def viewable_targets(real: str) -> list[dict]:
    """Everyone the rank guard could allow, for the picker. `start()` re-checks
    authorization server-side regardless of what the picker offered."""
    my_rank = rank_of(real)
    with SessionLocal() as db:
        rows = db.query(Account).filter(Account.active.is_(True)).order_by(Account.username)
        return [
            {"username": a.username, "label": a.display_name}
            for a in rows
            if a.username != real and rank_of(a.username) < my_rank
        ]


def _audit(action: str, real: str, target: str, mode: str) -> None:
    log.info("audit %s: real=%s target=%s mode=%s", action, real, target, mode)


def verify_and_effective(request: Request) -> str | None:
    """Re-authorize any active view-as (fail-closed), then return the EFFECTIVE
    username for this request. Called by the identity resolvers on every
    request — never read the session's user directly for data decisions."""
    session = request.session
    if not session.get("user"):
        return None
    bw_view_as.verify(
        session,
        can_view_as=can_view_as,
        rank_of=rank_of,
        target_valid=target_valid,
        audit=_audit,
    )
    return bw_view_as.effective_username(session)


def start(request: Request, target: str, mode: str = "readonly") -> None:
    """Begin impersonation. `mode='act'` is owner-only: acting writes real rows
    under the target's name, which is a testing tool, not a delegation one."""
    real = bw_view_as.real_username(request.session)
    if mode == "act" and not levels.is_owner(real):
        raise ViewAsError("Only the app owner may act as another user.", "FORBIDDEN")
    bw_view_as.start(
        request.session,
        target,
        can_view_as=can_view_as,
        rank_of=rank_of,
        target_valid=target_valid,
        mode=mode,
        audit=_audit,
    )
    _report(real, bw_view_as.effective_username(request.session), mode=mode, active=True)


def stop(request: Request) -> None:
    session = request.session
    real = bw_view_as.real_username(session)
    target = bw_view_as.effective_username(session)  # capture BEFORE stopping
    was_active = bw_view_as.is_impersonating(session)
    bw_view_as.stop(session, audit=_audit)
    if was_active:
        _report(real, target, active=False)


def heartbeat(request: Request) -> None:
    """Keep the central oversight row alive while impersonating. Called from
    /api/me after verify has run, so a just-auto-stopped view-as never reports."""
    session = request.session
    if bw_view_as.is_impersonating(session):
        _report(
            bw_view_as.real_username(session),
            bw_view_as.effective_username(session),
            mode=bw_view_as.mode(session),
            active=True,
        )


def me_fields(request: Request, label_of=None) -> dict:
    """The standard SPA block, with the drop-in's `mode` key renamed so it can
    never collide with anything else in /api/me."""
    fields = bw_view_as.me_fields(request.session, label=label_of)
    fields["view_as_mode"] = fields.pop("mode")
    return fields


def is_impersonating(request: Request) -> bool:
    return bw_view_as.is_impersonating(request.session)


def can_write(request: Request) -> bool:
    return bw_view_as.can_write(request.session)


def real_username(request: Request) -> str | None:
    return bw_view_as.real_username(request.session)


def _report(real: str, target: str, mode: str = "readonly", active: bool = True) -> None:
    """Owner oversight on the central Live page. Display-only, best-effort."""
    if not get_settings().has_bw_client:
        return
    try:
        bw_auth.report_impersonation(real, target, mode=mode, active=active)
    except Exception as exc:  # noqa: BLE001 - oversight must never break the app
        log.warning("report_impersonation failed: %s", exc)
