"""
Playbook Embedding Service — Phase 4 飛輪冷啟動修復
====================================================
ADR-067 延伸: Playbook 向量持久化到 PostgreSQL playbook_embeddings 表

職責:
  - 啟動時掃描 APPROVED Playbooks，重建 Redis 向量快取
  - 同步持久化到 playbook_embeddings (pgvector) 供跨重啟使用

呼叫方: main.py lifespan (asyncio.create_task — 非阻塞)

2026-04-10 Claude Sonnet 4.6 Asia/Taipei
修正 (首席架構師審查 2026-04-10):
  C1: _persist_embeddings_to_db 改用 PlaybookEmbeddingRepository (積木化修復)
  I2: 補齊 _persist_embeddings_to_db 型別標注
  I3: embedding 格式顯式格式化，防止 pgvector 解析錯誤
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import structlog

if TYPE_CHECKING:
    from src.models.playbook import Playbook
    from src.services.playbook_rag import PlaybookRAGService

logger = structlog.get_logger(__name__)


async def ensure_playbook_embeddings_indexed() -> None:
    """
    確保所有 APPROVED Playbooks 都有向量索引。

    執行步驟:
    1. 從 PlaybookService 取得所有 APPROVED Playbooks
    2. 呼叫 PlaybookRAGService.reindex_all_playbooks → 更新 Redis 向量快取
    3. 將向量持久化到 playbook_embeddings (pgvector) 表
    """
    try:
        from src.models.playbook import PlaybookStatus
        from src.services.playbook_service import get_playbook_service
        from src.services.playbook_rag import get_playbook_rag_service

        playbook_service = get_playbook_service()
        playbooks, _total = await playbook_service.list_playbooks(
            status=PlaybookStatus.APPROVED, limit=500
        )

        if not playbooks:
            logger.info("playbook_embedding_indexing_skipped", reason="no approved playbooks")
            return

        logger.info("playbook_embedding_indexing_start", count=len(playbooks))

        # Step 1: 重建 Redis 向量快取
        rag_service = await get_playbook_rag_service()
        success, failed = await rag_service.reindex_all_playbooks(playbooks)

        logger.info("playbook_embedding_redis_done", success=success, failed=failed)

        # Step 2: 持久化到 PostgreSQL playbook_embeddings 表
        await _persist_embeddings_to_db(rag_service, playbooks)

    except Exception as e:
        logger.warning("playbook_embedding_indexing_error", error=str(e))


async def _persist_embeddings_to_db(
    rag_service: "PlaybookRAGService",
    playbooks: "list[Playbook]",
) -> None:
    """
    將 Redis 向量快取同步寫入 playbook_embeddings DB 表 (持久化層)。

    C1 修正: 改用 PlaybookEmbeddingRepository，Service 不直接操作 SQL。
    I3 修正: embedding 格式由 Repository 層統一處理，防止 pgvector 解析錯誤。
    """
    try:
        from src.db.base import get_db_context
        from src.repositories.playbook_embedding_repository import PlaybookEmbeddingRepository

        persisted = 0
        skipped = 0

        async with get_db_context() as db:
            repo = PlaybookEmbeddingRepository(db)

            for playbook in playbooks:
                try:
                    embedding = await rag_service.get_playbook_embedding(playbook.playbook_id)
                    if not embedding:
                        skipped += 1
                        continue

                    sp = playbook.symptom_pattern
                    alert_names = list(sp.alert_names) if sp else []
                    keywords = list(sp.keywords) if sp else []

                    ok = await repo.upsert(
                        playbook_id=playbook.playbook_id,
                        embedding=embedding,
                        alert_names=alert_names,
                        keywords=keywords,
                    )
                    if ok:
                        persisted += 1
                    else:
                        skipped += 1

                except Exception as e:
                    logger.warning(
                        "playbook_embedding_persist_error",
                        playbook_id=playbook.playbook_id,
                        error=str(e),
                    )
                    skipped += 1

            await db.commit()

        logger.info("playbook_embedding_db_done", persisted=persisted, skipped=skipped)

    except Exception as e:
        logger.warning("playbook_embedding_db_error", error=str(e))
