"""배포 영향 분석 — CMDB CI 의존성 그래프 BFS 탐색."""
from __future__ import annotations

import logging
from collections import deque
from typing import List

logger = logging.getLogger(__name__)

MAX_DEPTH = 3


async def analyze_deploy_impact(ci_id: int, db) -> dict:
    """
    배포 대상 CI로부터 의존하는 모든 서비스/기관을 BFS로 탐색.

    Returns:
        {
          "ci_id": int,
          "ci_name": str,
          "affected_cis": [{"ci_id", "ci_name", "ci_type", "relation_type", "depth"}],
          "affected_institutions": [str],
          "risk_level": "LOW"|"MEDIUM"|"HIGH"|"CRITICAL",
          "risk_reason": str,
          "recommendation": str
        }
    """
    from models import ConfigItem, CIRelation, Institution
    from sqlalchemy import select, or_

    root = await db.get(ConfigItem, ci_id)
    if not root:
        raise ValueError(f"CI ID {ci_id}를 찾을 수 없습니다.")

    affected = []
    visited = {ci_id}
    queue = deque([(ci_id, 0)])
    affected_inst_ids = set()
    if root.inst_id:
        affected_inst_ids.add(root.inst_id)

    while queue:
        current_id, depth = queue.popleft()
        if depth >= MAX_DEPTH:
            continue

        # 현재 CI에서 출발하는 관계 조회 (DEPENDS_ON, USES, RUNS_ON 등)
        relations = (await db.execute(
            select(CIRelation)
            .where(or_(
                CIRelation.from_ci_id == current_id,
                CIRelation.to_ci_id == current_id,
            ))
        )).scalars().all()

        for rel in relations:
            next_id = rel.to_ci_id if rel.from_ci_id == current_id else rel.from_ci_id
            if next_id in visited:
                continue
            visited.add(next_id)

            next_ci = await db.get(ConfigItem, next_id)
            if not next_ci:
                continue

            affected.append({
                "ci_id":         next_ci.id,
                "ci_name":       next_ci.name,
                "ci_type":       next_ci.ci_type,
                "relation_type": rel.relation_type if hasattr(rel, "relation_type") else "RELATED",
                "depth":         depth + 1,
            })

            if next_ci.inst_id:
                affected_inst_ids.add(next_ci.inst_id)

            queue.append((next_id, depth + 1))

    # 영향받는 기관명 수집
    inst_names: List[str] = []
    for iid in affected_inst_ids:
        inst = await db.get(Institution, iid)
        if inst:
            inst_names.append(inst.inst_name)

    # 리스크 레벨 산정
    count = len(affected)
    if count == 0:
        risk_level = "LOW"
        risk_reason = "영향받는 CI 없음"
        recommendation = "배포를 안전하게 진행할 수 있습니다."
    elif count <= 3:
        risk_level = "MEDIUM"
        risk_reason = f"영향 CI {count}개"
        recommendation = "담당자 확인 후 배포를 진행하세요."
    elif count <= 8:
        risk_level = "HIGH"
        risk_reason = f"영향 CI {count}개 — 다수 서비스 영향"
        recommendation = "CAB 검토 후 유지보수 시간대에 배포하세요."
    else:
        risk_level = "CRITICAL"
        risk_reason = f"영향 CI {count}개 — 광범위한 서비스 영향"
        recommendation = "P1 수준 변경 관리 절차를 따르세요. 긴급 배포 금지."

    return {
        "ci_id":                  root.id,
        "ci_name":                root.name,
        "ci_type":                root.ci_type,
        "affected_cis":           affected,
        "affected_institutions":  inst_names,
        "risk_level":             risk_level,
        "risk_reason":            risk_reason,
        "recommendation":         recommendation,
    }
