"""RAG Client - REST client for PDF RAG WebApp."""

import time
from pathlib import Path

import requests

from .logging_config import get_logger

DEFAULT_RAG_URL = "https://pdf-rag-webapp-tztzmlgglq-de.a.run.app"

logger = get_logger("rag_client")


class RAGError(Exception):
    """RAG API error."""

    def __init__(self, message: str, status_code: int = 0):
        super().__init__(message)
        self.status_code = status_code


class RAGClient:
    """REST client for PDF RAG WebApp."""

    def __init__(self, base_url: str = DEFAULT_RAG_URL, timeout: int = 30):
        self.base_url = base_url.rstrip("/")
        self.timeout = timeout

    def upload(self, file_path: Path) -> dict:
        """Upload a PDF file.

        Returns:
            dict with doc_id, job_id, filename
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileNotFoundError(f"File not found: {file_path}")
        if not file_path.suffix.lower() == ".pdf":
            raise ValueError(f"Only PDF files are supported: {file_path}")

        with open(file_path, "rb") as f:
            response = requests.post(
                f"{self.base_url}/api/documents/upload",
                files={"file": (file_path.name, f, "application/pdf")},
                timeout=self.timeout,
            )

        if response.status_code != 200:
            raise RAGError(f"Upload failed: {response.text}", response.status_code)

        return response.json()

    def get_job_status(self, job_id: str) -> dict:
        """Get processing job status."""
        response = requests.get(
            f"{self.base_url}/api/jobs/{job_id}/status",
            timeout=self.timeout,
        )

        if response.status_code != 200:
            raise RAGError(f"Failed to get job status: {response.text}", response.status_code)

        return response.json()

    def wait_for_job(self, job_id: str, poll_interval: float = 2.0, timeout: int = 600) -> dict:
        """Poll job status until complete or error.

        Args:
            job_id: Job ID from upload
            poll_interval: Seconds between polls
            timeout: Max seconds to wait

        Returns:
            Final job status dict
        """
        start = time.time()
        while True:
            status = self.get_job_status(job_id)
            stage = status.get("stage", "")

            if stage == "complete":
                return status
            if stage == "error":
                raise RAGError(f"Processing failed: {status.get('message', 'unknown error')}")

            if time.time() - start > timeout:
                raise RAGError(f"Timeout waiting for job {job_id} (stage: {stage})")

            time.sleep(poll_interval)

    def search(self, question: str, doc_id: str | None = None, top_k: int = 15) -> dict:
        """Search documents.

        Args:
            question: Search query
            doc_id: Optional document ID to limit search
            top_k: Number of results (default 15)

        Returns:
            dict with question, contexts, total
        """
        payload: dict = {"question": question, "top_k": top_k}
        if doc_id:
            payload["doc_id"] = doc_id

        response = requests.post(
            f"{self.base_url}/api/search",
            json=payload,
            timeout=self.timeout,
        )

        if response.status_code != 200:
            raise RAGError(f"Search failed: {response.text}", response.status_code)

        return response.json()

    def list_documents(self) -> list:
        """List all documents."""
        response = requests.get(
            f"{self.base_url}/api/documents",
            timeout=self.timeout,
        )

        if response.status_code != 200:
            raise RAGError(f"Failed to list documents: {response.text}", response.status_code)

        return response.json()

    def delete_document(self, doc_id: str) -> bool:
        """Delete a document."""
        response = requests.delete(
            f"{self.base_url}/api/documents/{doc_id}",
            timeout=self.timeout,
        )

        if response.status_code != 200:
            raise RAGError(f"Failed to delete document: {response.text}", response.status_code)

        return True
