from typing import Any, Dict, Optional

from backend import schemas
from backend.database.base import db
from backend.database.models import DerivedDocument


def get_derived_documents(conversation_id: str, user_id: str):
    if not conversation_id or not user_id:
        return None
    with db.session.begin():
        docs = (
            db.session.query(DerivedDocument)
            .filter(DerivedDocument.conv_id == conversation_id, DerivedDocument.user_id == user_id)
            .all()
        )
        if docs:
            return [schemas.DerivedDocument.model_validate(d, from_attributes=True) for d in docs]


def get_derived_document_by_path(document_path: str, user_id: str):
    """Return one derived document for a user-owned attachment path, if it exists."""
    if not document_path or not user_id:
        return None
    with db.session.begin():
        doc = (
            db.session.query(DerivedDocument)
            .filter(DerivedDocument.document_path == document_path, DerivedDocument.user_id == user_id)
            .first()
        )
        if doc:
            return schemas.DerivedDocument.model_validate(doc, from_attributes=True)
        return None


def upsert_derived_document(
    conv_id: str,
    user_id: str,
    document_name: str,
    document_path: str,
    metadata: Optional[Dict[str, Any]] = None,
) -> DerivedDocument:
    """
    Insert or update a derived document record.
    """
    with db.session.begin():
        payload = metadata if metadata is not None else {"snapshots": []}
        obj = (
            db.session.query(DerivedDocument)
            .filter_by(
                conv_id=conv_id,
                user_id=user_id,
                document_name=document_name,
                document_path=document_path,
            )
            .first()
        )
        if obj:
            obj.document_metadata = payload
        else:
            obj = DerivedDocument(
                conv_id=conv_id,
                user_id=user_id,
                document_name=document_name,
                document_path=document_path,
                document_metadata=payload,
            )
            db.session.add(obj)
        db.session.flush()
        return schemas.DerivedDocument.model_validate(obj, from_attributes=True)


def delete_derived_document_by_source_path(document_path: str, user_id: Optional[str] = None) -> bool:
    if not user_id or not document_path:
        return False
    with db.session.begin():
        doc_meta = (
            db.session.query(DerivedDocument)
            .filter(DerivedDocument.document_path == document_path, DerivedDocument.user_id == user_id)
            .first()
        )
        if doc_meta:
            db.session.delete(doc_meta)
            return True
        return False
