"""FastAPI dependency injection wiring.

All service and repository instances are created here. No business logic.
"""
from __future__ import annotations

from typing import Optional

import structlog
from fastapi import Depends, Header, HTTPException

from config import settings
from export.validator import ExportValidator
from export.scanner import IDExportScanner
from repositories.user_repository import UserRepository
from repositories.conversion_repository import ConversionRepository
from services.scan_service import ScanService
from services.conversion_service import ConversionService
from services.user_service import UserService
from services.payment_service import PaymentService

log = structlog.get_logger()

# ── Singletons (stateless services safe to share) ─────────────────────────────

_validator          = ExportValidator()
_scanner            = IDExportScanner()
_scan_service       = ScanService(_validator, _scanner)
_user_repo          = UserRepository()
_conversion_repo    = ConversionRepository()
_user_service       = UserService(_user_repo)
_payment_service    = PaymentService()
_conversion_service = ConversionService(_scan_service, _conversion_repo)


# ── Service getters ───────────────────────────────────────────────────────────

def get_scan_service() -> ScanService:
    return _scan_service

def get_conversion_service() -> ConversionService:
    return _conversion_service

def get_user_service() -> UserService:
    return _user_service

def get_payment_service() -> PaymentService:
    return _payment_service


# ── Admin token ───────────────────────────────────────────────────────────────

def get_admin_token() -> str:
    """Return the PocketBase admin token from settings.

    This token is used for server-side writes (creating conversion/purchase
    records) that must bypass normal user permission rules.
    """
    return getattr(settings, 'pocketbase_admin_token', '')


# ── Auth dependencies ─────────────────────────────────────────────────────────

async def get_optional_user(
    authorization: Optional[str] = Header(None),
) -> Optional[dict]:
    """Extract and validate the Bearer token. Returns user dict or None.

    Used on endpoints where auth is optional (e.g. scan — no credits needed).
    """
    if not authorization or not authorization.startswith('Bearer '):
        return None
    token = authorization.split(' ', 1)[1]
    try:
        user = await _user_repo.get_by_token(token)
        return user
    except Exception:
        return None


async def get_current_user_or_401(
    authorization: Optional[str] = Header(None),
) -> dict:
    """Extract and validate the Bearer token. Raises 401 if missing or invalid.

    Used on endpoints that require authentication (convert, users/me, payments).
    """
    if not authorization or not authorization.startswith('Bearer '):
        raise HTTPException(401, 'Authentication required')
    token = authorization.split(' ', 1)[1]
    try:
        return await _user_repo.get_by_token(token)
    except Exception:
        raise HTTPException(401, 'Invalid or expired token')
