from __future__ import annotations

from dataclasses import dataclass
from typing import Protocol

import psycopg

from rag_agent.config import AppConfig
from rag_agent.index.embeddings import EmbeddingClient
from rag_agent.retrieval.search import search_similar


class LLMClient(Protocol):
    def generate(self, prompt: str, model: str) -> str:
        raise NotImplementedError


@dataclass
class StubLLMClient:
    def generate(self, prompt: str, model: str) -> str:
        return (
            "LLM client is not configured. "
            "Replace StubLLMClient with a real implementation."
        )


def build_prompt(question: str, contexts: list[str]) -> str:
    joined = "\n\n".join(contexts)
    return (
        "You are a RAG assistant. Use the context below to answer the question.\n\n"
        f"Context:\n{joined}\n\n"
        f"Question: {question}\nAnswer:"
    )


def answer_query(
    conn: psycopg.Connection,
    config: AppConfig,
    embedding_client: EmbeddingClient,
    llm_client: LLMClient,
    question: str,
    top_k: int = 5,
    story_id: int | None = None,
) -> str:
    query_embedding = embedding_client.embed_texts([question])[0]
    results = search_similar(
        conn, query_embedding, top_k=top_k, story_id=story_id
    )
    contexts = [f"Source: {item.path}\n{item.content}" for item in results]
    prompt = build_prompt(question, contexts)
    return llm_client.generate(prompt, model=config.llm_model)
