"""
Playbook Embedding Repository — pgvector 持久化層
=================================================
C1 修正 (首席架構師審查 2026-04-10 Claude Sonnet 4.6 Asia/Taipei):
  違規修復: playbook_embedding_service.py 直接 db.execute(text(...)) 繞過 Repository 層
  解法: 移至此 Repository，Service 層透過此介面存取

職責: playbook_embeddings 表的 CRUD (pgvector)
對應遷移: migrations/flywheel_playbook_embeddings.sql
"""

from __future__ import annotations

import structlog
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession

logger = structlog.get_logger(__name__)


class PlaybookEmbeddingRepository:
    """
    Playbook Embedding Repository

    職責: playbook_embeddings 表 CRUD
    使用 pgvector 儲存 bge-m3:latest 1024 維向量（ADR-110 2026-05-04 升級自 768 維）

    Args:
        db: SQLAlchemy AsyncSession (DI 注入)
    """

    def __init__(self, db: AsyncSession) -> None:
        self._db = db

    async def upsert(
        self,
        playbook_id: str,
        embedding: list[float],
        alert_names: list[str],
        keywords: list[str],
    ) -> bool:
        """
        新增或更新 Playbook 向量 (UPSERT)。

        pgvector 格式: '[x,y,z,...]' 字串
        ON CONFLICT (playbook_id) → 更新向量快照與 updated_at

        Args:
            playbook_id: Playbook ID
            embedding: 1024 維浮點向量 (list[float])，bge-m3:latest
            alert_names: 索引時的 alert_names 快照
            keywords: 索引時的 keywords 快照

        Returns:
            True 表示成功
        """
        try:
            # 顯式格式化保證 pgvector 可解析，避免 str(list) 空格差異
            vec_str = "[" + ",".join(str(float(x)) for x in embedding) + "]"

            await self._db.execute(
                text("""
                    INSERT INTO playbook_embeddings
                        (playbook_id, embedding, alert_names, keywords, indexed_at, updated_at)
                    VALUES
                        (:playbook_id, :embedding, :alert_names, :keywords, NOW(), NOW())
                    ON CONFLICT (playbook_id) DO UPDATE SET
                        embedding   = EXCLUDED.embedding,
                        alert_names = EXCLUDED.alert_names,
                        keywords    = EXCLUDED.keywords,
                        updated_at  = NOW()
                """),
                {
                    "playbook_id": playbook_id,
                    "embedding": vec_str,
                    "alert_names": alert_names,
                    "keywords": keywords,
                },
            )
            return True

        except Exception as e:
            logger.warning(
                "playbook_embedding_upsert_failed",
                playbook_id=playbook_id,
                error=str(e),
            )
            return False

    async def delete(self, playbook_id: str) -> bool:
        """刪除 Playbook 向量記錄。"""
        try:
            await self._db.execute(
                text("DELETE FROM playbook_embeddings WHERE playbook_id = :pid"),
                {"pid": playbook_id},
            )
            return True
        except Exception as e:
            logger.warning(
                "playbook_embedding_delete_failed",
                playbook_id=playbook_id,
                error=str(e),
            )
            return False
