from __future__ import annotations

from dataclasses import asdict

from fastapi import HTTPException, status

from app.domain.permissions import build_permission_context
from app.repositories.directus.client import DirectusClient
from app.schemas.auth import AuthenticatedUser, PermissionContextRead


class AuthContextService:
    """Validates Directus-issued tokens and normalizes user context.

    FastAPI remains the formal API entrypoint, but Directus is still the source
    of truth for login/session/role data. This service is the seam between them.
    """

    # Keep the first auth bootstrap intentionally conservative.
    # Directus `/users/me` on this project reliably returns the core user/role
    # fields below, while deeper `user_group.*` expansions can collapse the
    # payload back to only `{id}`. We can layer group/domain permissions back in
    # later once the base admin flow is verified end to end.
    me_fields = [
        "email",
        "first_name",
        "id",
        "role.id",
        "role.name",
        "status",
    ]

    def __init__(self, client: DirectusClient | None = None) -> None:
        self.client = client or DirectusClient()

    async def get_authenticated_user(self, access_token: str) -> AuthenticatedUser:
        if not access_token:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Missing access token.",
            )

        me = await self.client.get_current_user(
            access_token=access_token,
            fields=self.me_fields,
        )
        if not me:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Unable to resolve current user from Directus.",
            )

        user_group = me.get("user_group") or {}
        permissions = user_group.get("domain_permissions") or []
        normalized_permissions = [str(permission) for permission in permissions]
        role = me.get("role") or {}
        permission_context = build_permission_context(
            role_name=role.get("name"),
            domain_permissions=normalized_permissions,
        )

        # Keep the normalized payload explicit so downstream services do not need
        # to know the exact nested Directus response shape.
        return AuthenticatedUser.model_validate(
            {
                **me,
                "domain_permissions": normalized_permissions,
                "permissions": PermissionContextRead.model_validate(asdict(permission_context)),
            }
        )
