"""
Scouter APM 연동 API 라우터

엔드포인트:
  GET /api/scouter/status         — Scouter 연결 상태 + 전체 요약
  GET /api/scouter/servers        — 모니터링 대상 서버 목록
  GET /api/scouter/servers/{hash}/metrics — 특정 서버 실시간 메트릭
  GET /api/scouter/servers/{hash}/services — 활성 서비스 목록
  GET /api/scouter/servers/{hash}/xlog     — 최근 트랜잭션 X-Log
  GET /api/scouter/alerts         — 경보 목록
  POST /api/scouter/agent/deploy  — Tomcat 에이전트 SSH 배포 (ADMIN/ENGINEER)
"""
from __future__ import annotations

import logging
import os
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession

from core.auth import get_current_user
from database import get_db
from models import User, UserRole

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/scouter", tags=["scouter"])


# ── 스키마 ───────────────────────────────────────────────────────────────────

class AgentDeployRequest(BaseModel):
    server_id:    int            # CMDB 서버 ID
    scouter_host: Optional[str] = None  # Scouter 서버 호스트 (기본: 환경변수)
    scouter_port: int = 6100     # Scouter 수집 포트 (기본: 6100)


# ── 엔드포인트 ───────────────────────────────────────────────────────────────

@router.get("/status")
async def scouter_status(
    current_user: User = Depends(get_current_user),
):
    """Scouter 연결 상태 및 전체 모니터링 현황 요약."""
    from core.scouter import get_summary, is_available
    available = await is_available()
    summary   = await get_summary()
    return {
        "connected": available,
        "host":      os.getenv("SCOUTER_HOST", ""),
        "port":      os.getenv("SCOUTER_HTTP_PORT", "6180"),
        **summary,
    }


@router.get("/servers")
async def list_servers(
    current_user: User = Depends(get_current_user),
):
    """모니터링 대상 객체(서버/서비스) 목록."""
    from core.scouter import get_object_list
    return {"servers": await get_object_list()}


@router.get("/servers/{obj_hash}/metrics")
async def server_metrics(
    obj_hash: int,
    current_user: User = Depends(get_current_user),
):
    """특정 서버 실시간 메트릭 (CPU, Heap, TPS, 응답시간)."""
    from core.scouter import get_server_metrics
    metrics = await get_server_metrics(obj_hash)
    if not metrics:
        raise HTTPException(404, "서버 메트릭을 가져올 수 없습니다.")
    return {"obj_hash": obj_hash, "metrics": metrics}


@router.get("/servers/{obj_hash}/services")
async def active_services(
    obj_hash: int,
    current_user: User = Depends(get_current_user),
):
    """활성 서비스 목록 (현재 처리 중인 요청)."""
    from core.scouter import get_active_services
    return {"services": await get_active_services(obj_hash)}


@router.get("/servers/{obj_hash}/xlog")
async def xlog(
    obj_hash: int,
    limit: int = 20,
    current_user: User = Depends(get_current_user),
):
    """최근 트랜잭션 X-Log 조회."""
    from core.scouter import get_xlog_recent
    return {"xlogs": await get_xlog_recent(obj_hash, limit)}


@router.get("/alerts")
async def alerts(
    obj_hash: Optional[int] = None,
    current_user: User = Depends(get_current_user),
):
    """Scouter 경보 목록."""
    from core.scouter import get_alert_list
    return {"alerts": await get_alert_list(obj_hash)}


@router.post("/agent/deploy")
async def deploy_agent(
    body: AgentDeployRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """
    Tomcat 서버에 Scouter 에이전트 SSH 배포 (ADMIN/ENGINEER 전용).

    배포 절차:
    1. CMDB에서 서버 SSH 접속 정보 조회 (AES-256-GCM 복호화)
    2. scouter-agent.jar 및 설정 파일 SFTP 전송
    3. Tomcat JAVA_OPTS에 -javaagent 옵션 추가
    4. Tomcat 재기동 (선택)
    """
    if current_user.role not in (UserRole.ADMIN, UserRole.ENGINEER):
        raise HTTPException(403, "ADMIN 또는 ENGINEER만 에이전트를 배포할 수 있습니다.")

    from models import Server
    from sqlalchemy import select

    srv = await db.get(Server, body.server_id)
    if not srv:
        raise HTTPException(404, f"서버 ID {body.server_id}를 찾을 수 없습니다.")

    scouter_host = body.scouter_host or os.getenv("SCOUTER_HOST", "localhost")
    scouter_port = body.scouter_port

    try:
        result = await _deploy_agent_ssh(srv, scouter_host, scouter_port, current_user.username)
        return {
            "message":    f"Scouter 에이전트 배포 완료: {srv.server_name}",
            "server":     srv.server_name,
            "scouter":    f"{scouter_host}:{scouter_port}",
            "deployed_at": result.get("deployed_at"),
            "restart_required": True,
        }
    except Exception as e:
        raise HTTPException(500, f"에이전트 배포 실패: {str(e)[:200]}")


async def _deploy_agent_ssh(srv, scouter_host: str, scouter_port: int, actor: str) -> dict:
    """SSH/SFTP로 Scouter 에이전트 파일 배포."""
    from datetime import datetime
    from core.ssh_exec import execute_ssh_command

    # GUARDIA_ROOT/setup/scouter/ 에서 에이전트 파일 확인
    agent_local = _find_agent_jar()
    if not agent_local:
        raise ValueError("scouter-agent.jar를 찾을 수 없습니다. setup/scouter/에 파일을 배치하세요.")

    # Scouter 에이전트 설정 파일 생성 (임시)
    conf_content = f"""
net.collector.ip={scouter_host}
net.collector.udp_port={scouter_port}
net.collector.tcp_port={scouter_port}
obj_name={srv.server_name}
trace_interservice_enabled=true
hook_method_patterns=io.guardia.*,com.agency.*
"""

    # 원격 배포 디렉토리
    remote_dir = "/app/scouter"

    # SSH로 디렉토리 생성
    result = await execute_ssh_command(
        srv.id,
        f"mkdir -p {remote_dir} && echo OK",
        timeout=30,
    )
    if not result.success:
        raise ValueError(f"원격 디렉토리 생성 실패: {result.error}")

    # 설정 파일 생성
    await execute_ssh_command(
        srv.id,
        f"cat > {remote_dir}/agent.conf << 'SCCONF'\n{conf_content}\nSCCONF",
        timeout=30,
    )

    # JAVA_OPTS 에 javaagent 옵션 추가 (Tomcat setenv.sh)
    javaagent_opts = (
        f'-javaagent:{remote_dir}/scouter-agent.jar '
        f'-Dscouter.config={remote_dir}/agent.conf'
    )
    setenv_cmd = f"""
SETENV=/app/tomcat/bin/setenv.sh
if [ -f "$SETENV" ]; then
    grep -q 'scouter' "$SETENV" || echo 'export JAVA_OPTS="$JAVA_OPTS {javaagent_opts}"' >> "$SETENV"
else
    echo '#!/bin/bash' > "$SETENV"
    echo 'export JAVA_OPTS="$JAVA_OPTS {javaagent_opts}"' >> "$SETENV"
    chmod +x "$SETENV"
fi
echo "setenv.sh 업데이트 완료"
"""
    await execute_ssh_command(srv.id, setenv_cmd, timeout=30)

    return {"deployed_at": datetime.utcnow().isoformat()}


def _find_agent_jar() -> str:
    """Scouter 에이전트 JAR 파일 탐색."""
    import pathlib
    candidates = [
        pathlib.Path(__file__).parent.parent.parent / "setup" / "scouter" / "scouter-agent.jar",
        pathlib.Path("/opt/scouter/agent/scouter-agent.jar"),
        pathlib.Path("/app/scouter/scouter-agent.jar"),
    ]
    for p in candidates:
        if p.exists():
            return str(p)
    return ""
