from fastapi import Depends, HTTPException, status, Header
from typing import List, Any, Optional, Annotated
from sqlalchemy.orm import Session
from app.db import models
from app.db.session import SessionLocal
from app.core.retrievers.base_retriever import Retriever
from app.core.services.document import DocumentService
from app.core.services.rag import RAGService
from app.core.vector_store.faiss_store import FaissVectorStore


# This is a dependency
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# Dependency to get current user object from X-User-ID header
async def get_current_user(
    db: Session = Depends(get_db),
    x_user_id: Annotated[Optional[str], Header()] = None
) -> models.User:
    if not x_user_id:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="X-User-ID header is missing"
        )
    
    user = db.query(models.User).filter(models.User.id == x_user_id).first()
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    
    from app.config import settings
    if not user.password_hash and not settings.OIDC_ENABLED:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Account disabled: OIDC is inactive and no password is set."
        )
        
    return user


async def get_current_admin(
    current_user: models.User = Depends(get_current_user)
) -> models.User:
    if current_user.role != "admin":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Admin role required"
        )
    return current_user


class ServiceContainer:
    """
    A flexible container for managing and providing various application services.
    Services are added dynamically using the `with_service` method.
    """
    def __init__(self):
        # Use a dictionary to store services, mapping their names to instances
        self._services = {}
        self.document_service = None
        self.rag_service = None

    def with_service(self, name: str, service: Any):
        """
        Adds a service to the container.

        Args:
            name (str): The name to assign to the service (e.g., 'tts_service').
            service (Any): The service instance to add.
        """
        setattr(self, name, service)
        return self

    def with_document_service(self, vector_store: Optional[FaissVectorStore]):
        """
        Adds a DocumentService instance to the container.
        """
        if vector_store:
            self.document_service = DocumentService(vector_store=vector_store)
        return self
    
    def with_rag_service(self, retrievers: List[Retriever], prompt_service = None, tool_service = None, node_registry_service = None):
        """
        Adds a RAGService instance to the container.
        """
        self.rag_service = RAGService(retrievers=retrievers, prompt_service=prompt_service, tool_service=tool_service, node_registry_service=node_registry_service)
        return self

    def __getattr__(self, name: str) -> Any:
        """
        Allows services to be accessed directly as attributes (e.g., container.rag_service).
        """
        raise AttributeError(f"'{self.__class__.__name__}' object has no service named '{name}'")