"""
스마트 알림 규칙 편집기 + 지능형 필터

노코드 방식으로 알림 규칙을 정의하고
AI 기반 스마트 필터로 알림 피로도를 관리한다.

엔드포인트:
  GET  /api/smart-notify/rules       — 규칙 목록
  POST /api/smart-notify/rules       — 규칙 생성
  PUT  /api/smart-notify/rules/{id}  — 규칙 수정
  DELETE /api/smart-notify/rules/{id}— 규칙 삭제
  POST /api/smart-notify/test/{id}   — 테스트 발송
  GET  /api/smart-notify/logs        — 발송 이력
  POST /api/smart-notify/silence     — 무음 기간 설정
  GET  /api/smart-notify/digest      — 일괄 요약 설정
"""
from __future__ import annotations

import json
import logging
from datetime import datetime
from typing import List, Optional

import httpx
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException
from pydantic import BaseModel, Field
from sqlalchemy import select, desc
from sqlalchemy.ext.asyncio import AsyncSession

from core.auth import get_current_user, require_admin_role
from database import get_db
from models import User, SmartNotifyRule, NotifyLog

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/smart-notify", tags=["스마트 알림"])

OLLAMA_URL = "http://localhost:11434"
ITSM_NOTIFY = "http://127.0.0.1:9001/api/messenger/webhook"


class NotifyRuleCreate(BaseModel):
    name: str = Field(..., max_length=200)
    trigger_type: str = Field(..., description="SR_CREATED|SR_UPDATED|INCIDENT|DRIFT|KPI_BREACH|CUSTOM")
    conditions: dict = Field(default_factory=dict)
    channels: List[str] = Field(default_factory=list, description="messenger|email|slack|kakao")
    priority_filter: str = Field("ALL", description="HIGH|MEDIUM|ALL")
    silence_hours: Optional[List[int]] = Field(None, description="무음 시간 목록 [22,23,0,1,...,7]")
    digest_mode: bool = Field(False, description="묶음 발송 모드")
    digest_interval_min: int = Field(60, description="묶음 발송 간격(분)")
    is_active: bool = True


class SilenceRequest(BaseModel):
    rule_id: Optional[int] = None   # None = 전체
    hours: List[int] = Field(..., description="무음 시간 [22,23,0,1,...,7]")


async def _send_to_messenger(message: str, room: str = "ops") -> bool:
    try:
        async with httpx.AsyncClient(timeout=5) as c:
            r = await c.post(ITSM_NOTIFY, json={
                "event": "smart_notify", "room": room,
                "success": True, "result_summary": message
            })
            return r.status_code == 200
    except Exception as e:
        logger.warning(f"메신저 알림 실패: {e}")
        return False


async def _ai_classify_importance(notification: dict) -> str:
    """Ollama로 알림 중요도 재평가 (HIGH/MEDIUM/LOW)."""
    try:
        async with httpx.AsyncClient(timeout=10) as c:
            r = await c.post(f"{OLLAMA_URL}/api/generate", json={
                "model": "llama3",
                "system": "IT 운영 알림 중요도 분류. HIGH/MEDIUM/LOW 중 하나만 답변.",
                "prompt": f"알림: {json.dumps(notification, ensure_ascii=False)[:200]}",
                "stream": False,
            })
            if r.status_code == 200:
                resp = r.json().get("response", "").strip().upper()
                if "HIGH" in resp: return "HIGH"
                if "LOW" in resp: return "LOW"
    except Exception:
        pass
    return "MEDIUM"


def _check_conditions(rule: SmartNotifyRule, event: dict) -> bool:
    """규칙 조건 충족 여부 확인."""
    conditions = rule.conditions or {}
    for key, expected in conditions.items():
        actual = event.get(key)
        if isinstance(expected, list):
            if actual not in expected: return False
        elif actual != expected:
            return False
    return True


def _is_silent_hour(rule: SmartNotifyRule) -> bool:
    """현재 시각이 무음 시간대인지 확인."""
    silent = rule.silence_hours
    if not silent:
        return False
    current_hour = datetime.utcnow().hour + 9  # KST
    current_hour = current_hour % 24
    return current_hour in silent


@router.get("/rules")
async def list_rules(
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_current_user),
):
    rows = await db.execute(
        select(SmartNotifyRule)
        .order_by(SmartNotifyRule.name)
    )
    rules = rows.scalars().all()
    return [
        {
            "id": r.id, "name": r.name, "trigger_type": r.trigger_type,
            "conditions": r.conditions, "channels": r.channels,
            "priority_filter": r.priority_filter,
            "silence_hours": r.silence_hours,
            "digest_mode": r.digest_mode,
            "is_active": r.is_active, "created_at": r.created_at,
        }
        for r in rules
    ]


@router.post("/rules")
async def create_rule(
    req: NotifyRuleCreate,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(require_admin_role),
):
    rule = SmartNotifyRule(
        
        name=req.name,
        trigger_type=req.trigger_type,
        conditions=req.conditions,
        channels=req.channels,
        priority_filter=req.priority_filter,
        silence_hours=req.silence_hours or [],
        digest_mode=req.digest_mode,
        digest_interval_min=req.digest_interval_min,
        is_active=req.is_active,
        created_at=datetime.utcnow(),
    )
    db.add(rule)
    await db.commit()
    await db.refresh(rule)
    return {"ok": True, "id": rule.id}


@router.put("/rules/{rule_id}")
async def update_rule(
    rule_id: int,
    req: NotifyRuleCreate,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(require_admin_role),
):
    row = await db.execute(
        select(SmartNotifyRule).where(SmartNotifyRule.id == rule_id, SmartNotifyRule.id > 0)
    )
    rule = row.scalar_one_or_none()
    if not rule:
        raise HTTPException(404)
    rule.name = req.name; rule.trigger_type = req.trigger_type
    rule.conditions = req.conditions; rule.channels = req.channels
    rule.priority_filter = req.priority_filter
    rule.silence_hours = req.silence_hours or []
    rule.digest_mode = req.digest_mode; rule.is_active = req.is_active
    await db.commit()
    return {"ok": True}


@router.delete("/rules/{rule_id}")
async def delete_rule(
    rule_id: int,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(require_admin_role),
):
    row = await db.execute(
        select(SmartNotifyRule).where(SmartNotifyRule.id == rule_id, SmartNotifyRule.id > 0)
    )
    rule = row.scalar_one_or_none()
    if not rule: raise HTTPException(404)
    await db.delete(rule); await db.commit()
    return {"ok": True}


@router.post("/test/{rule_id}")
async def test_rule(
    rule_id: int,
    background_tasks: BackgroundTasks,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_current_user),
):
    """테스트 알림 발송."""
    row = await db.execute(
        select(SmartNotifyRule).where(SmartNotifyRule.id == rule_id, SmartNotifyRule.id > 0)
    )
    rule = row.scalar_one_or_none()
    if not rule: raise HTTPException(404)

    msg = f"[테스트] 알림 규칙 '{rule.name}' 테스트 발송"
    sent = False
    if "messenger" in (rule.channels or []):
        sent = await _send_to_messenger(msg)
    log = NotifyLog(
        rule_id=rule.id, channel="messenger",
        recipient="ops", message=msg,
        status="SENT" if sent else "FAILED",
        sent_at=datetime.utcnow(),
    )
    db.add(log); await db.commit()
    return {"ok": sent, "message": msg}


@router.get("/logs")
async def notify_logs(
    limit: int = 50,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_current_user),
):
    rows = await db.execute(
        select(NotifyLog, SmartNotifyRule.name.label("rule_name")).join(
            SmartNotifyRule, NotifyLog.rule_id == SmartNotifyRule.id, isouter=True
        )
        .order_by(desc(NotifyLog.sent_at)).limit(limit)
    )
    return [
        {"id": r.NotifyLog.id, "rule": r.rule_name,
         "channel": r.NotifyLog.channel, "status": r.NotifyLog.status,
         "message": r.NotifyLog.message[:100], "sent_at": r.NotifyLog.sent_at}
        for r in rows.all()
    ]


@router.post("/silence")
async def set_silence(
    req: SilenceRequest,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(require_admin_role),
):
    """무음 시간대 설정."""
    q = select(SmartNotifyRule)
    if req.rule_id:
        q = q.where(SmartNotifyRule.id == req.rule_id)
    rows = await db.execute(q)
    rules = rows.scalars().all()
    for rule in rules:
        rule.silence_hours = req.hours
    await db.commit()
    return {"ok": True, "updated": len(rules), "silence_hours": req.hours}
