class LoggingCallbackHandler:
    def on_ingest_start(self, file_path): print(f"[RAG] Starting ingestion: {file_path}")
    def on_ingest_end(self, file_path, chunk_count, duration_ms=None): print(f"[RAG] Finished ingestion. Chunks: {chunk_count} ({duration_ms} ms)")
    def on_ingest_summary(self, summary): print(f"[RAG] Ingest summary: processed={summary['processed']}, ok={summary['succeeded']}, failed={summary['failed']}")
    def on_chunking_start(self, strategy): print(f"[RAG] Chunking strategy: {strategy}")
    def on_embedding_start(self, count): print(f"[RAG] Embedding {count} chunks...")
    def on_retrieval_start(self, query): print(f"[RAG] Querying: \"{query}\"")
    def on_retrieval_end(self, count, duration_ms=None): print(f"[RAG] Retrieved {count} docs ({duration_ms} ms)")
    def on_reranking_start(self, count): print(f"[RAG] Reranking {count} docs...")
    def on_reranking_end(self, count): print(f"[RAG] Reranking finished. Keeping top {count}.")
    def on_generation_start(self, prompt_preview=None): print("[RAG] Generating answer...")
    def on_generation_end(self, answer_preview=None, duration_ms=None): print(f"[RAG] Answer generated ({duration_ms} ms)")
    def on_error(self, err): print(f"[RAG] Error: {getattr(err, 'message', str(err))}")

class StructuredLoggingCallbackHandler:
    def on_ingest_start(self, file_path): print({ 'event': 'ingest_start', 'filePath': file_path })
    def on_ingest_end(self, file_path, chunk_count, duration_ms=None): print({ 'event': 'ingest_end', 'filePath': file_path, 'chunkCount': chunk_count, 'durationMs': duration_ms })
    def on_ingest_summary(self, summary): print({ 'event': 'ingest_summary', **summary })
    def on_chunking_start(self, strategy): print({ 'event': 'chunking_start', 'strategy': strategy })
    def on_embedding_start(self, count): print({ 'event': 'embedding_start', 'count': count })
    def on_retrieval_start(self, query): print({ 'event': 'retrieval_start', 'query': query })
    def on_retrieval_end(self, count, duration_ms=None): print({ 'event': 'retrieval_end', 'count': count, 'durationMs': duration_ms })
    def on_reranking_start(self, count): print({ 'event': 'reranking_start', 'count': count })
    def on_reranking_end(self, count): print({ 'event': 'reranking_end', 'count': count })
    def on_generation_start(self, prompt_preview=None): print({ 'event': 'generation_start', 'promptPreview': str(prompt_preview)[:120] if prompt_preview else None })
    def on_generation_end(self, answer_preview=None, duration_ms=None): print({ 'event': 'generation_end', 'answerPreview': str(answer_preview)[:120] if answer_preview else None, 'durationMs': duration_ms })
    def on_error(self, err): print({ 'event': 'error', 'message': getattr(err, 'message', str(err)) })
