"""
단위 테스트: 예측 용량 계획 (Predictive Capacity Planning)
- predictive_capacity 라우터 임포트 검증
- 신규 ORM 모델 3개 테이블명 검증
- Pydantic 스키마 필드 검증
- 예측 로직 헬퍼 함수 검증
- 경보 기준 상수 검증
- 예산 사이클 분기 권고 문구 검증
"""
from __future__ import annotations


# ── 임포트 가능 여부 ──────────────────────────────────────────────────────────

def test_module_import():
    """predictive_capacity 모듈이 오류 없이 임포트되는지 확인."""
    from routers import predictive_capacity
    assert predictive_capacity.router is not None


def test_router_prefix():
    """라우터 prefix가 /api/capacity-ai인지 확인."""
    from routers.predictive_capacity import router
    assert router.prefix == "/api/capacity-ai"


# ── ORM 모델 검증 ─────────────────────────────────────────────────────────────

def test_orm_models_import():
    """신규 ORM 모델 3개가 임포트되는지 확인."""
    from models import CapacityForecast, CapacityRecommendation, BudgetCycle
    assert CapacityForecast.__tablename__ == "tb_capacity_forecast"
    assert CapacityRecommendation.__tablename__ == "tb_capacity_recommendation"
    assert BudgetCycle.__tablename__ == "tb_budget_cycle"


def test_capacity_forecast_columns():
    """CapacityForecast 필수 컬럼 존재 확인."""
    from models import CapacityForecast
    cols = {c.name for c in CapacityForecast.__table__.columns}
    required = {"id", "server_name", "metric", "forecast_days", "current_value",
                "predicted_value", "confidence", "trend", "created_at"}
    assert required.issubset(cols)


def test_capacity_recommendation_columns():
    """CapacityRecommendation 필수 컬럼 존재 확인."""
    from models import CapacityRecommendation
    cols = {c.name for c in CapacityRecommendation.__table__.columns}
    required = {"id", "server_name", "rec_type", "urgency", "reason",
                "estimated_cost", "status", "approved_by", "created_at"}
    assert required.issubset(cols)


def test_budget_cycle_columns():
    """BudgetCycle 필수 컬럼 존재 확인."""
    from models import BudgetCycle
    cols = {c.name for c in BudgetCycle.__table__.columns}
    required = {"id", "year", "quarter", "budget_infra", "budget_license",
                "budget_cloud", "spent", "forecast_spend", "status", "created_at"}
    assert required.issubset(cols)


# ── Pydantic 스키마 검증 ──────────────────────────────────────────────────────

def test_pydantic_schemas_import():
    """Pydantic 스키마 4종 임포트 확인."""
    from models import (
        CapacityForecastOut,
        CapacityRecommendationOut,
        BudgetCycleOut,
        BudgetCycleCreate,
    )
    assert CapacityForecastOut is not None
    assert CapacityRecommendationOut is not None
    assert BudgetCycleOut is not None
    assert BudgetCycleCreate is not None


def test_budget_cycle_create_defaults():
    """BudgetCycleCreate 기본값 검증."""
    from models import BudgetCycleCreate
    body = BudgetCycleCreate(year=2026)
    assert body.quarter == 1
    assert body.budget_infra == 0.0
    assert body.status == "planning"


def test_capacity_forecast_out_fields():
    """CapacityForecastOut 필수 필드 검증."""
    from models import CapacityForecastOut
    fields = set(CapacityForecastOut.model_fields.keys())
    required = {"id", "server_name", "metric", "forecast_days",
                "current_value", "predicted_value", "confidence", "trend", "created_at"}
    assert required.issubset(fields)


# ── 헬퍼 함수 검증 ────────────────────────────────────────────────────────────

def test_get_budget_recommendation_all_quarters():
    """모든 분기(1~4)에 대해 권고 문구가 반환되는지 확인."""
    from routers.predictive_capacity import get_budget_recommendation
    for q in (1, 2, 3, 4):
        msg = get_budget_recommendation(q)
        assert isinstance(msg, str)
        assert len(msg) > 0


def test_get_budget_recommendation_unknown_quarter():
    """잘못된 분기 값에 대해 기본 메시지 반환 확인."""
    from routers.predictive_capacity import get_budget_recommendation
    msg = get_budget_recommendation(99)
    assert msg == "예산 계획 수립 중"


def test_trend_label_increasing():
    """일별 증가율 > 0.5 → increasing 판정."""
    from routers.predictive_capacity import _trend_label
    assert _trend_label(0.8) == "increasing"
    assert _trend_label(1.2) == "increasing"


def test_trend_label_stable():
    """일별 증가율 0.0~0.5 → stable 판정."""
    from routers.predictive_capacity import _trend_label
    assert _trend_label(0.3) == "stable"
    assert _trend_label(0.0) == "stable"


def test_trend_label_decreasing():
    """일별 증가율 < -0.1 → decreasing 판정."""
    from routers.predictive_capacity import _trend_label
    assert _trend_label(-0.5) == "decreasing"
    assert _trend_label(-1.0) == "decreasing"


def test_urgency_from_predicted_immediate():
    """30일 내 80% 초과 → immediate 긴급도."""
    from routers.predictive_capacity import _urgency_from_predicted
    assert _urgency_from_predicted(30, 82.0) == "immediate"
    assert _urgency_from_predicted(25, 85.0) == "immediate"


def test_urgency_from_predicted_30days():
    """60일 내 90% 초과 → 30days 긴급도."""
    from routers.predictive_capacity import _urgency_from_predicted
    # 30일 내 80% 미만이지만 60일 내 90% 초과
    assert _urgency_from_predicted(60, 92.0) == "30days"


def test_urgency_from_predicted_60days():
    """90일 내 95% 초과 → 60days 긴급도."""
    from routers.predictive_capacity import _urgency_from_predicted
    # 30/60일 기준 미달, 90일 기준 충족
    assert _urgency_from_predicted(90, 96.0) == "60days"


def test_urgency_from_predicted_none():
    """임계치 미달 시 None 반환."""
    from routers.predictive_capacity import _urgency_from_predicted
    # 모든 기준 미달
    assert _urgency_from_predicted(90, 50.0) is None


# ── 경보 기준 상수 검증 ───────────────────────────────────────────────────────

def test_alert_rules_structure():
    """경보 규칙 상수(_ALERT_RULES)가 3개 항목이며 올바른 순서인지 확인."""
    from routers.predictive_capacity import _ALERT_RULES
    assert len(_ALERT_RULES) == 3
    days_list = [r[0] for r in _ALERT_RULES]
    thresholds = [r[1] for r in _ALERT_RULES]
    # 기간이 짧을수록 임계치가 낮아야 함 (더 빠른 경고)
    assert days_list == sorted(days_list)
    assert thresholds == sorted(thresholds)


# ── 엔드포인트 경로 검증 ──────────────────────────────────────────────────────

def test_all_routes_registered():
    """9개 엔드포인트가 모두 등록되어 있는지 확인."""
    from routers.predictive_capacity import router
    paths = {r.path for r in router.routes}
    expected = {
        "/api/capacity-ai/forecast",
        "/api/capacity-ai/forecast/{days}",
        "/api/capacity-ai/recommendations",
        "/api/capacity-ai/recommendations/{rec_id}/approve",
        "/api/capacity-ai/recommendations/{rec_id}/reject",
        "/api/capacity-ai/budget-cycle",
        "/api/capacity-ai/alerts",
    }
    assert expected.issubset(paths)


def test_forecast_post_and_get_routes():
    """forecast 경로에 GET과 POST가 모두 존재하는지 확인."""
    from routers.predictive_capacity import router
    forecast_methods: set = set()
    for r in router.routes:
        if r.path == "/api/capacity-ai/forecast":
            forecast_methods.update(r.methods)
    assert "GET" in forecast_methods
    assert "POST" in forecast_methods


def test_budget_cycle_post_and_get_routes():
    """budget-cycle 경로에 GET과 POST가 모두 존재하는지 확인."""
    from routers.predictive_capacity import router
    bc_methods: set = set()
    for r in router.routes:
        if r.path == "/api/capacity-ai/budget-cycle":
            bc_methods.update(r.methods)
    assert "GET" in bc_methods
    assert "POST" in bc_methods
