"""Who the caller is: the two request-scoped resolvers the whole app runs on.

Sources of truth: this module, `app/services/sessions.py`, `app/services/view_as.py`,
`docs/ACCOUNTS.md`.

`optional_user` is the EFFECTIVE username (the impersonated one while a View As is active);
`real_user` is the actually-signed-in one. Both are `(request) -> str | None`, so they work as
FastAPI dependencies and as the identity hooks the vendored router expects. Data and
permission decisions use `optional_user`; anything that logs, reports or renders "who you
are" uses `real_user`. A session on a disabled account resolves to nobody.
"""

from __future__ import annotations

from dataclasses import dataclass

from fastapi import HTTPException
from sqlalchemy import select
from starlette.requests import Request

from app import db as appdb
from app.models import Account
from app.services import sessions


@dataclass(frozen=True)
class Actor:
    """The EFFECTIVE account a write is attributed to: its id for the who-column, its display
    name for the text column (a snapshot; the raw record)."""

    id: int
    username: str
    display_name: str


def real_user(request: Request) -> str | None:
    row = sessions.of_request(request)
    if row is None or not row.active or not row.username:
        return None
    return row.username


def optional_user(request: Request) -> str | None:
    """Runs the View As re-authorisation first (fail-closed: an impersonation that is no
    longer allowed auto-stops here), then returns the impersonated user while one is
    active, else the real one."""
    from app.services import view_as

    if real_user(request) is None:
        return None
    return view_as.verify_and_effective(request)


def actor(request: Request) -> Actor:
    """Who a write is attributed to: the effective account under View As, else the real one.
    The access policy admits no write without a session; this is the route's own belt."""
    effective = optional_user(request)
    row = sessions.of_request(request)
    if effective is None or row is None:
        raise HTTPException(status_code=401, detail={"error_code": "NOT_SIGNED_IN", "summary": "Sign in to do this."})
    if effective == row.username:
        return Actor(row.account_id, row.username, row.display_name)
    with appdb.SessionLocal() as db:
        found = db.execute(select(Account.id, Account.display_name).where(Account.username == effective)).first()
    if found is None:
        raise HTTPException(status_code=401, detail={"error_code": "NOT_SIGNED_IN", "summary": "Sign in to do this."})
    return Actor(found[0], effective, found[1])
