"""Composition of agent access services and transport dependencies."""

import secrets

import structlog
from fastapi import Depends, HTTPException, Request
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from redis import asyncio as aioredis
from sqlalchemy.ext.asyncio import AsyncSession

from src.config import get_settings
from src.core.database import get_db
from src.core.dependencies import get_productive_access_policy
from src.core.exceptions import UnauthorizedError
from src.dependencies import get_redis_client
from src.domain.agent_access.repository import AgentRepository
from src.domain.agent_access.service import AgentAccessService
from src.domain.projects.repository import ProjectRepository
from src.domain.workspaces.facades import WorkspaceFacadeImpl
from src.domain.workspaces.repository import MembershipRepository, WorkspaceRepository


def require_agent_access(request: Request):
    settings = get_settings()
    supplied = request.headers.get("X-P2HS-Agent-Proxy", "")
    if (
        not settings.agent_access_enabled
        or not settings.agent_proxy_secret
        or not secrets.compare_digest(supplied.encode(), settings.agent_proxy_secret.encode())
    ):
        raise HTTPException(status_code=404, detail="Not Found")


async def make_agent_service(db: AsyncSession, redis: aioredis.Redis | None = None):
    return AgentAccessService(
        AgentRepository(db),
        WorkspaceFacadeImpl(WorkspaceRepository(db), MembershipRepository(db)),
        ProjectRepository(db),
        await get_productive_access_policy(db),
        redis,
    )


async def get_billing_delegation_service(db: AsyncSession = Depends(get_db)):
    from src.domain.agent_access.billing_delegation import BillingDelegationService
    from src.domain.auth.repository import UserRepository
    from src.integrations.email_provider import get_email_provider

    settings = get_settings()
    return BillingDelegationService(
        AgentRepository(db),
        WorkspaceFacadeImpl(WorkspaceRepository(db), MembershipRepository(db)),
        UserRepository(db),
        email_provider=get_email_provider(),
        app_url=settings.app_url,
    )


async def get_agent_service(
    db: AsyncSession = Depends(get_db),
    redis: aioredis.Redis = Depends(get_redis_client),
):
    return await make_agent_service(db, redis)


async def get_agent_principal(
    credentials: HTTPAuthorizationCredentials | None = Depends(HTTPBearer(auto_error=False)),
    service: AgentAccessService = Depends(get_agent_service),
):
    if not credentials or credentials.scheme.lower() != "bearer":
        raise UnauthorizedError("Agent access token required")
    principal = await service.authenticate(credentials.credentials)
    # Enriches every log emitted for the rest of this request (including the
    # generic request_completed line) with who is acting, for read-tool audit.
    structlog.contextvars.bind_contextvars(agent_grant_id=str(principal.id))
    return principal
