"""
Dual-mode authentication for endpoints reachable both by the SaaS
customer dashboard (JWT-authenticated) and by service/integration
callers (API-key-authenticated).

/analyze is the main consumer of this — a logged-in customer using the
dashboard hits it with a Bearer token, while a server-to-server
integration the client sets up later can keep using an API key. Either
is accepted; the resulting AuthContext tells the route handler which
one was used and, if a user, who they are — so the analysis can be
correctly attributed and saved against their account.
"""

from dataclasses import dataclass

from fastapi import Depends, Header, Request
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.auth_tokens import decode_token
from app.core.config import get_settings
from app.core.exceptions import AuthenticationError
from app.db.models import User
from app.db.session import get_db_session

settings = get_settings()


@dataclass
class AuthContext:
    auth_type: str  # "user" | "api_key"
    user: User | None = None
    api_key: str | None = None

    @property
    def user_id(self) -> str | None:
        return self.user.id if self.user else None


async def get_auth_context(
    request: Request,
    db: AsyncSession = Depends(get_db_session),
    x_api_key: str | None = Header(None, alias="X-API-Key"),
) -> AuthContext:
    auth_header = request.headers.get("Authorization")

    if auth_header and auth_header.lower().startswith("bearer "):
        token = auth_header[7:]
        payload = decode_token(token, expected_type="access")
        user_id = payload.get("sub")

        result = await db.execute(select(User).where(User.id == user_id))
        user = result.scalar_one_or_none()

        if user is None:
            raise AuthenticationError(message="User account no longer exists")
        if not user.is_active:
            raise AuthenticationError(message="This account has been deactivated. Contact support.")

        return AuthContext(auth_type="user", user=user)

    if x_api_key:
        valid_keys = settings.valid_api_keys_list
        if not valid_keys:
            if settings.is_production:
                raise AuthenticationError(message="Service misconfigured. Contact support.")
            return AuthContext(auth_type="api_key", api_key=x_api_key)  # dev convenience

        if x_api_key not in valid_keys:
            raise AuthenticationError(message="Invalid or missing API key")
        return AuthContext(auth_type="api_key", api_key=x_api_key)

    raise AuthenticationError(
        message="Authentication required. Provide either a Bearer token (logged-in user) "
                "or an X-API-Key header (service integration)."
    )
