"""
Config Drift Detection API Router - Phase 25 P2
================================================
GitOps 守門員 HTTP 端點

leWOOOgo 積木化原則:
- Router 層只做 HTTP 轉發
- 不直接存取 Redis/DB
- 業務邏輯委託給 Service 層

版本: v1.0
建立: 2026-04-04 (台北時區)
建立者: Claude Code (Phase 25 P2)
"""

from fastapi import APIRouter, BackgroundTasks, HTTPException

from src.models.drift import (
    DriftListResponse,
    DriftReport,
    DriftScanRequest,
    DriftScanResponse,
)
from src.repositories.drift_repository import get_drift_repository
from src.services.drift_analyzer import get_drift_analyzer
from src.services.drift_detector import get_drift_detector
from src.services.drift_interpreter import get_drift_interpreter
from src.services.drift_remediator import get_drift_remediator

router = APIRouter(prefix="/drift", tags=["drift"])

# 2026-04-09 Claude Sonnet 4.6: B4 drift_reports 持久化 — 改用 DB repository


@router.post("/scan", response_model=DriftScanResponse, summary="觸發漂移掃描")
async def trigger_drift_scan(
    request: DriftScanRequest,
    background_tasks: BackgroundTasks,
) -> DriftScanResponse:
    """
    觸發 Config Drift 掃描

    - 比對 Git YAML vs K8s 實際狀態
    - Nemotron 分析漂移意圖
    - 高/中嚴重度漂移自動推送 Telegram

    適合由 Gitea CD Webhook 或手動呼叫觸發
    """
    detector = get_drift_detector()
    analyzer = get_drift_analyzer()

    repo = get_drift_repository()
    all_items = []
    last_report: DriftReport | None = None

    for namespace in request.namespaces:
        raw_report = await detector.scan(namespace, triggered_by=request.triggered_by)
        classified_report = analyzer.classify(raw_report)
        all_items.extend(classified_report.items)

        # 持久化到 DB
        await repo.save(classified_report)

        if analyzer.needs_alert(classified_report):
            background_tasks.add_task(_analyze_and_notify, classified_report)
            last_report = classified_report

    # 若多 namespace，彙總第一個 report 的計數
    if last_report:
        return DriftScanResponse(
            report_id=last_report.report_id,
            summary=last_report.summary,
            high_count=last_report.high_count,
            medium_count=last_report.medium_count,
            info_count=last_report.info_count,
            has_critical_drift=last_report.has_critical_drift,
        )

    return DriftScanResponse(
        report_id="no-drift",
        summary="無漂移",
        high_count=0,
        medium_count=0,
        info_count=0,
        has_critical_drift=False,
    )


@router.get("/reports", response_model=DriftListResponse, summary="列出最近漂移報告")
async def list_drift_reports() -> DriftListResponse:
    """列出最近 50 筆漂移報告（倒序）"""
    repo = get_drift_repository()
    items = await repo.list_recent(limit=50)
    return DriftListResponse(items=items, total=len(items))


@router.post("/reports/{report_id}/rollback", summary="覆蓋回 Git 狀態")
async def rollback_drift(report_id: str) -> dict:
    """
    將 K8s 狀態覆蓋回 Git YAML（kubectl apply）

    人工確認後才執行，DriftRemediator 負責確定性修復
    """
    repo = get_drift_repository()
    report = await repo.get(report_id)
    if not report:
        raise HTTPException(status_code=404, detail=f"Report {report_id} not found")

    remediator = get_drift_remediator()
    result = await remediator.rollback(report)
    return result


@router.post("/reports/{report_id}/adopt", summary="承認變更並建立 Git PR")
async def adopt_drift(report_id: str) -> dict:
    """
    承認 K8s 漂移，透過 Gitea PR API 將漂移寫回 Git

    2026-04-05 Claude Code: ADR-057 實作 — 改用 Gitea PR API（不再 git push main）
    流程: 建立 drift/adopt-* branch → commit YAML 注解 → 建立 PR → Telegram 通知 SRE
    """
    repo = get_drift_repository()
    report = await repo.get(report_id)
    if not report:
        raise HTTPException(status_code=404, detail=f"Report {report_id} not found")

    from src.services.drift_adopt_service import get_drift_adopt_service
    adopt_svc = get_drift_adopt_service()
    result = await adopt_svc.adopt(report)
    return result


# =============================================================================
# Internal endpoint（供 K8s CronJob 呼叫）
# =============================================================================

@router.post("/internal/scan", include_in_schema=False, summary="CronJob 觸發掃描")
async def internal_scan(background_tasks: BackgroundTasks) -> dict:
    """內部 CronJob 端點，每小時自動掃描 awoooi-prod"""
    from src.core.config import get_settings
    settings = get_settings()
    namespaces = getattr(settings, "DRIFT_SCAN_NAMESPACES", "awoooi-prod").split(",")

    background_tasks.add_task(
        _run_full_scan,
        [ns.strip() for ns in namespaces],
    )
    return {"status": "scan_triggered", "namespaces": namespaces}


# =============================================================================
# Background helpers
# =============================================================================

async def _analyze_and_notify(report: DriftReport) -> None:
    """背景：Nemotron 意圖分析 + Telegram 推送 + Phase 30 AI 人話摘要"""
    import structlog as _structlog
    _logger = _structlog.get_logger(__name__)
    try:
        interpreter = get_drift_interpreter()

        interpretation = await interpreter.analyze(report)
        repo = get_drift_repository()
        await repo.update_interpretation(report.report_id, interpretation)

        # ADR-075: drift_narrator_service 負責發送 TYPE-4D 卡片（含按鈕）
        # 舊的 send_text() 已移除，改由 narrate_and_notify() 統一處理
        try:
            from src.services.drift_narrator_service import get_drift_narrator_service
            narrator = get_drift_narrator_service()
            await narrator.narrate_and_notify(report, interpretation)
        except Exception as e:
            _logger.warning("drift_narrator_failed", error=str(e))

    except Exception as e:
        import structlog
        structlog.get_logger(__name__).error("drift_analyze_notify_failed", error=str(e))


async def _run_full_scan(namespaces: list[str]) -> None:
    """背景：完整漂移掃描"""
    detector = get_drift_detector()
    analyzer = get_drift_analyzer()

    repo = get_drift_repository()
    for namespace in namespaces:
        try:
            raw = await detector.scan(namespace, triggered_by="cron")
            classified = analyzer.classify(raw)
            await repo.save(classified)

            if analyzer.needs_alert(classified):
                await _analyze_and_notify(classified)
        except Exception as e:
            import structlog
            structlog.get_logger(__name__).error(
                "full_scan_namespace_failed", namespace=namespace, error=str(e)
            )
