"""Rebuild the Postgres full-text ``search_vector`` over the document corpus.

FRREP-SR001/004 — author names, abstracts, extracted body text, and the
geographic / subject facets are folded into ``search_vector`` by
``apps.repository.search.indexes.update_search_vector``. The bulk Drupal import
populated documents without (re)building their vectors, so author and facet
searches miss those rows. This command loops the per-document reindex over the
whole corpus (optionally scoped) so the imported backlog becomes findable.

Examples::

    python manage.py reindex_repository_search
    python manage.py reindex_repository_search --collection theses
    python manage.py reindex_repository_search --since 2026-06-01
    python manage.py reindex_repository_search --missing-only
"""

from __future__ import annotations

from django.core.management.base import BaseCommand, CommandError
from django.utils.dateparse import parse_datetime, parse_date
from django.utils import timezone


class Command(BaseCommand):
    help = "Rebuild the full-text search_vector for repository documents."

    def add_arguments(self, parser):
        parser.add_argument(
            "--collection",
            dest="collection",
            default=None,
            help="Limit to a single collection slug.",
        )
        parser.add_argument(
            "--since",
            dest="since",
            default=None,
            help="Only reindex documents created on/after this ISO date (e.g. 2026-06-01).",
        )
        parser.add_argument(
            "--missing-only",
            action="store_true",
            dest="missing_only",
            help="Only reindex documents whose search_vector is currently NULL/empty.",
        )
        parser.add_argument(
            "--batch-size",
            type=int,
            default=200,
            help="Progress reporting cadence (rows per status line). Default 200.",
        )

    def handle(self, *args, **options):
        from apps.repository.documents.models import Document
        from apps.repository.search.indexes import update_search_vector

        qs = Document.objects.all().order_by("pk")

        if options["collection"]:
            qs = qs.filter(collection__slug=options["collection"])
            if not qs.exists():
                raise CommandError(
                    f"No documents in collection '{options['collection']}'."
                )

        if options["since"]:
            since = parse_datetime(options["since"]) or parse_date(options["since"])
            if since is None:
                raise CommandError(
                    f"Could not parse --since value '{options['since']}' (use ISO date)."
                )
            if hasattr(since, "tzinfo") and timezone.is_naive(since):
                since = timezone.make_aware(since)
            qs = qs.filter(created_at__gte=since)

        if options["missing_only"]:
            qs = qs.filter(search_vector__isnull=True)

        total = qs.count()
        if total == 0:
            self.stdout.write(self.style.WARNING("No matching documents to reindex."))
            return

        batch = max(1, options["batch_size"])
        self.stdout.write(f"Reindexing {total} document(s)…")

        done = 0
        failed = 0
        # Iterate by pk to keep memory flat over very large corpora.
        for pk in qs.values_list("pk", flat=True).iterator():
            if update_search_vector(pk):
                done += 1
            else:
                failed += 1
            if (done + failed) % batch == 0:
                self.stdout.write(f"  … {done + failed}/{total}")

        msg = f"Reindexed {done} document(s)."
        if failed:
            msg += f" {failed} could not be indexed (no longer present)."
        self.stdout.write(self.style.SUCCESS(msg))
