"""Incremental norm vector synchronization service."""
from __future__ import annotations

import asyncio
from typing import Optional
from uuid import UUID

from qdrant_client.models import PointStruct

from normbase.models.norm import Norm
from normbase.services.norm_text_builder import (
    BUILDER_VERSION,
    build_norm_nl_text,
    build_norm_subject_metadata,
    build_norm_tag_groups,
    build_norm_text_hash,
)
from normbase.services.qdrant_service import QdrantService
from normbase.infra.llm import get_llm_provider


class NormVectorService:
    """Best-effort vector sync for norm CRUD lifecycle."""

    def __init__(self, qdrant_service: Optional[QdrantService] = None, llm_provider=None):
        self._qdrant_service = qdrant_service
        self._qdrant_unavailable = False
        self._llm_provider = llm_provider
        self._llm_unavailable = False

    def _get_qdrant_service(self) -> Optional[QdrantService]:
        if self._qdrant_service is not None:
            return self._qdrant_service
        if self._qdrant_unavailable:
            return None
        try:
            self._qdrant_service = QdrantService()
        except Exception as e:
            self._qdrant_unavailable = True
            print(f"Norm vector sync disabled (Qdrant unavailable): {e}")
            return None
        return self._qdrant_service

    def _get_llm_provider(self):
        if self._llm_provider is not None:
            return self._llm_provider
        if self._llm_unavailable:
            return None
        try:
            self._llm_provider = get_llm_provider()
        except Exception as e:
            self._llm_unavailable = True
            print(f"Norm vector sync disabled (LLM unavailable): {e}")
            return None
        return self._llm_provider

    async def sync_norm(self, norm: Norm) -> None:
        """Upsert active norms, delete non-active norms."""
        if not norm or not getattr(norm, "id", None):
            return
        status = str(getattr(norm, "status", "")).strip().lower()
        if status != "active":
            await self.delete_norm(norm.id)
            return

        qdrant = self._get_qdrant_service()
        if qdrant is None:
            return
        llm_provider = self._get_llm_provider()
        if llm_provider is None:
            return

        try:
            text = build_norm_nl_text(norm)
            vector = await llm_provider.async_get_embedding(text)
            text_hash = build_norm_text_hash(text)
            tags = build_norm_tag_groups(norm)
            roles, agents = build_norm_subject_metadata(norm)
            await asyncio.to_thread(
                qdrant.client.upsert,
                collection_name=qdrant.collection_name,
                points=[
                    PointStruct(
                        id=str(norm.id),
                        vector=vector,
                        payload={
                            "text": text,
                            "text_hash": text_hash,
                            "builder_version": BUILDER_VERSION,
                            "field_id": str(norm.field_id) if norm.field_id else None,
                            "title": norm.title,
                            "norm_type": norm.norm_type,
                            "formality_level": norm.formality_level,
                            "context": norm.context,
                            "status": norm.status,
                            "tags": tags,
                            "roles": roles,
                            "agents": agents,
                        },
                    )
                ],
            )
        except Exception as e:
            print(f"Norm vector upsert error ({getattr(norm, 'id', '')}): {e}")

    async def delete_norm(self, norm_id: UUID | str) -> None:
        """Delete norm vector entry."""
        qdrant = self._get_qdrant_service()
        if qdrant is None:
            return
        try:
            await asyncio.to_thread(qdrant.delete_norm, str(norm_id))
        except Exception as e:
            print(f"Norm vector delete error ({norm_id}): {e}")
