"""
Management command to run a search query from the command line.

Usage:
    python manage.py search "how do neural networks work"
    python manage.py search "motor wiring" --library-uid abc123
    python manage.py search "quantum physics" --limit 5 --no-rerank
"""

import json
import logging

from django.conf import settings
from django.core.management.base import BaseCommand

logger = logging.getLogger(__name__)


class Command(BaseCommand):
    help = "Run a hybrid search query against the Mnemosyne knowledge graph."

    def add_arguments(self, parser):
        parser.add_argument("query", type=str, help="Search query text")
        parser.add_argument(
            "--library-uid",
            type=str,
            default="",
            help="Scope search to a specific library UID",
        )
        parser.add_argument(
            "--library-type",
            type=str,
            default="",
            help="Scope search to a library type (fiction, technical, etc.)",
        )
        parser.add_argument(
            "--limit",
            type=int,
            default=0,
            help="Maximum results (default: from settings)",
        )
        parser.add_argument(
            "--no-rerank",
            action="store_true",
            help="Skip re-ranking (return fusion results only)",
        )
        parser.add_argument(
            "--types",
            type=str,
            default="vector,fulltext,graph",
            help="Comma-separated search types (default: vector,fulltext,graph)",
        )
        parser.add_argument(
            "--json",
            action="store_true",
            help="Output results as JSON",
        )

    def handle(self, *args, **options):
        from library.services.search import SearchRequest, SearchService

        query = options["query"]
        limit = options["limit"] or getattr(settings, "SEARCH_DEFAULT_LIMIT", 20)
        search_types = [t.strip() for t in options["types"].split(",") if t.strip()]
        rerank = not options["no_rerank"]

        self.stdout.write(
            self.style.HTTP_INFO(
                f'Searching: "{query}" (types={search_types}, limit={limit}, rerank={rerank})'
            )
        )

        request = SearchRequest(
            query=query,
            library_uid=options["library_uid"] or None,
            library_type=options["library_type"] or None,
            # Unrestricted: the CLI is a shell-level operator tool; it
            # bypasses the MCP bearer-resolver and sees every library.
            # ``resolved_libraries=None`` is the "no auth clause" branch
            # (see ``library/services/search.py::_RESOLVED_LIBRARIES_CLAUSE``).
            resolved_libraries=None,
            search_types=search_types,
            limit=limit,
            vector_top_k=getattr(settings, "SEARCH_VECTOR_TOP_K", 50),
            fulltext_top_k=getattr(settings, "SEARCH_FULLTEXT_TOP_K", 30),
            rerank=rerank,
            include_images=True,
        )

        service = SearchService()
        response = service.search(request)

        if options["json"]:
            self._output_json(response)
        else:
            self._output_text(response)

    def _output_text(self, response):
        """Format results as human-readable text."""
        self.stdout.write("")
        self.stdout.write(
            self.style.SUCCESS(
                f"Found {len(response.candidates)} results "
                f"({response.total_candidates} candidates, "
                f"{response.search_time_ms:.0f}ms, "
                f"types={response.search_types_used}, "
                f"reranked={response.reranker_used})"
            )
        )
        self.stdout.write("")

        for i, c in enumerate(response.candidates, 1):
            self.stdout.write(
                self.style.WARNING(f"  [{i}] {c.item_title} (chunk #{c.chunk_index})")
            )
            self.stdout.write(f"      Score: {c.score:.6f}  Source: {c.source}")
            if c.library_type:
                self.stdout.write(f"      Type: {c.library_type}")
            preview = c.text_preview[:200].replace("\n", " ")
            self.stdout.write(f"      {preview}")
            self.stdout.write("")

        if response.images:
            self.stdout.write(
                self.style.SUCCESS(f"\nImage results: {len(response.images)}")
            )
            for img in response.images:
                self.stdout.write(
                    f"  [{img.image_type}] {img.item_title} — {img.description[:80]}  "
                    f"(score: {img.score:.4f})"
                )

    def _output_json(self, response):
        """Format results as JSON."""
        data = {
            "query": response.query,
            "total_candidates": response.total_candidates,
            "search_time_ms": response.search_time_ms,
            "reranker_used": response.reranker_used,
            "reranker_model": response.reranker_model,
            "search_types_used": response.search_types_used,
            "candidates": [
                {
                    "chunk_uid": c.chunk_uid,
                    "item_uid": c.item_uid,
                    "item_title": c.item_title,
                    "library_type": c.library_type,
                    "text_preview": c.text_preview[:200],
                    "chunk_index": c.chunk_index,
                    "score": c.score,
                    "source": c.source,
                }
                for c in response.candidates
            ],
            "images": [
                {
                    "image_uid": img.image_uid,
                    "item_title": img.item_title,
                    "image_type": img.image_type,
                    "description": img.description[:200],
                    "score": img.score,
                }
                for img in response.images
            ],
        }
        self.stdout.write(json.dumps(data, indent=2))
