"""
Work execution router — work-log CRUD, SSH simulation, completion + messenger notify.
"""
import asyncio
import json
from datetime import datetime
from typing import List, Optional

try:
    import httpx
    _HTTPX = True
except ImportError:
    _HTTPX = False

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

from core.auth import get_current_user
from database import get_db
from models import (
    AuditLog, Institution, Rating, Server, SRRequest, SRStatus,
    User, WorkActionType, WorkLog, WorkLogOut, WorkStepIn, compute_log_hash,
)

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

# ── Messenger webhook URL (same machine) ──────────────────────────────────────
MESSENGER_WEBHOOK = "http://localhost:8000/api/messenger/webhook"
NOTIFY_ROOM       = "ops"   # 알림 채널


# ── SSH 시뮬레이션 템플릿 ─────────────────────────────────────────────────────
_SSH_SIM: dict[str, list[dict]] = {
    "RESTART": [
        {"action": WorkActionType.SSH_CONNECT,
         "content": "SSH 접속 시도 (opsagent@{server}:22)",
         "result": "Connected to {server} — OpenSSH_8.7, RHEL 8.9"},
        {"action": WorkActionType.SSH_EXEC,
         "content": "systemctl stop tomcat9 && sleep 2 && systemctl start tomcat9",
         "result": "● tomcat9.service: active (running) since {ts}"},
        {"action": WorkActionType.HEALTH_CHECK,
         "content": "curl -sf http://localhost:8080/health -o /dev/null -w '%{http_code}'",
         "result": "200 OK — 응답 시간 42ms"},
    ],
    "DEPLOY": [
        {"action": WorkActionType.SSH_CONNECT,
         "content": "SFTP 접속 시도 (opsagent@{server}:22)",
         "result": "sftp> Connected to {server}"},
        {"action": WorkActionType.SOURCE_MOD,
         "content": "파일 전송: put -r ./classes /app/was/webapps/ROOT/WEB-INF/classes/",
         "result": "전송 완료 — 23 files, 1.4 MB (0.8s)"},
        {"action": WorkActionType.SSH_EXEC,
         "content": "systemctl reload tomcat9",
         "result": "Reload OK — 클래스 파일 적용됨"},
        {"action": WorkActionType.HEALTH_CHECK,
         "content": "curl -sf http://localhost:8080/actuator/health",
         "result": '{"status":"UP","components":{"db":{"status":"UP"}}}'},
    ],
    "LOG": [
        {"action": WorkActionType.SSH_CONNECT,
         "content": "SSH 접속 ({server}:22) — 로그 분석 모드",
         "result": "Connected"},
        {"action": WorkActionType.SSH_EXEC,
         "content": "tail -n 200 /app/was/logs/catalina.out | grep -E 'ERROR|WARN'",
         "result": (
             "[ERROR] 2026-05-24 17:32:11 ORA-01555: snapshot too old\n"
             "[WARN]  2026-05-24 17:33:05 Connection pool exhausted (200/200)\n"
             "[ERROR] 2026-05-24 17:34:22 java.lang.OutOfMemoryError: GC overhead"
         )},
    ],
    "DEFAULT": [
        {"action": WorkActionType.SSH_CONNECT,
         "content": "SSH 접속 ({server}:22)",
         "result": "Connected"},
        {"action": WorkActionType.SSH_EXEC,
         "content": "작업 수행 중…",
         "result": "명령 실행 완료"},
    ],
}


async def _write_audit(db: AsyncSession, sr_id: str, actor: str,
                        action: str, detail: str) -> None:
    result = await db.execute(
        select(AuditLog).where(AuditLog.sr_id == sr_id)
                         .order_by(AuditLog.id.desc()).limit(1)
    )
    last = result.scalars().first()
    prev_hash = last.log_hash if last else None
    ts = datetime.now().isoformat()
    log_hash = compute_log_hash(prev_hash, actor, action, detail, ts)
    db.add(AuditLog(sr_id=sr_id, actor=actor, action=action,
                    detail=detail, prev_hash=prev_hash, log_hash=log_hash))


async def _notify_messenger(sr: SRRequest, work_summary: str) -> None:
    """완료 시 메신저 webhook 호출."""
    if not _HTTPX:
        return
    payload = {
        "event":        "itsm_complete",
        "room":         NOTIFY_ROOM,
        "sr_id":        sr.sr_id,
        "title":        sr.title,
        "sr_type":      sr.sr_type,
        "requested_by": sr.requested_by,
        "target_server": sr.target_server or "—",
        "result_summary": work_summary,
    }
    try:
        async with httpx.AsyncClient(timeout=5.0) as client:
            await client.post(MESSENGER_WEBHOOK, json=payload)
    except Exception:
        pass  # 메신저 미동작 시 무시


# ── Endpoints ─────────────────────────────────────────────────────────────────

@router.get("/{sr_id}", response_model=List[WorkLogOut])
async def list_work_logs(sr_id: str, db: AsyncSession = Depends(get_db),
                          _u: User = Depends(get_current_user)):
    result = await db.execute(
        select(WorkLog).where(WorkLog.sr_id == sr_id).order_by(WorkLog.created_at)
    )
    return result.scalars().all()


@router.post("/{sr_id}/step", response_model=WorkLogOut, status_code=201)
async def add_work_step(sr_id: str, payload: WorkStepIn,
                         db: AsyncSession = Depends(get_db),
                         _u: User = Depends(get_current_user)):
    r = await db.execute(select(SRRequest).where(SRRequest.sr_id == sr_id))
    if not r.scalars().first():
        raise HTTPException(404, "SR을 찾을 수 없습니다.")
    log = WorkLog(sr_id=sr_id, **payload.model_dump())
    db.add(log)
    await db.commit()
    await db.refresh(log)
    return log


@router.post("/{sr_id}/simulate")
async def simulate_work(sr_id: str, engineer: str = "GUARDiA-AI",
                         db: AsyncSession = Depends(get_db),
                         current_user: User = Depends(get_current_user)):
    """
    전체 작업 흐름 시뮬레이션:
    CMDB 확인 → SSH 접속 → 작업 실행 → 헬스체크 → SR COMPLETED → 메신저 알림
    """
    r = await db.execute(select(SRRequest).where(SRRequest.sr_id == sr_id))
    sr = r.scalars().first()
    if not sr:
        raise HTTPException(404, "SR을 찾을 수 없습니다.")

    ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    server = sr.target_server or "UNKNOWN-SRV"

    # ── Step 1: CMDB 자산 확인 ──────────────────────────────────────────────
    srv_info = ""
    if sr.target_server:
        sv = await db.execute(
            select(Server).where(Server.server_name == sr.target_server)
        )
        sv_obj = sv.scalars().first()
        if sv_obj:
            srv_info = f"{sv_obj.server_role} | {sv_obj.os_type} {sv_obj.os_version} | SSH:22"

    cmdb_log = WorkLog(
        sr_id=sr_id, engineer=engineer,
        action_type=WorkActionType.CMDB_CHECK,
        content=f"CMDB 자산 조회: {server}",
        result=srv_info or f"{server} — CMDB 등록 서버 확인됨",
        is_success=True,
    )
    db.add(cmdb_log)

    # ── SR 상태 자동 전이: RECEIVED/PARSED → PENDING_APPROVAL → APPROVED ────
    auto_approve = sr.status in (
        SRStatus.RECEIVED, SRStatus.PARSED,
        SRStatus.PENDING_APPROVAL, SRStatus.APPROVED
    )
    if sr.status in (SRStatus.RECEIVED, SRStatus.PARSED):
        sr.status = SRStatus.PENDING_APPROVAL
        await _write_audit(db, sr_id, engineer, "AUTO_PENDING", "시뮬레이션: 승인 대기 전이")
    if sr.status == SRStatus.PENDING_APPROVAL:
        sr.status = SRStatus.APPROVED
        await _write_audit(db, sr_id, "AUTO_APPROVE", "SR_APPROVED", "시뮬레이션: 자동 승인")

    # IN_PROGRESS 전이
    sr.status = SRStatus.IN_PROGRESS
    sr.updated_at = datetime.now()
    await _write_audit(db, sr_id, engineer, "SR_STARTED", "작업 시작")
    await db.flush()

    # ── Step 2~N: SR type별 SSH 시뮬레이션 ───────────────────────────────────
    steps = _SSH_SIM.get(sr.sr_type, _SSH_SIM["DEFAULT"])
    result_summary = ""
    for step in steps:
        wlog = WorkLog(
            sr_id=sr_id, engineer=engineer,
            action_type=step["action"],
            content=step["content"].format(server=server, ts=ts),
            result=step["result"].format(server=server, ts=ts),
            is_success=True,
        )
        db.add(wlog)
        result_summary = wlog.result

    # ── Step Final: RESULT 기록 ───────────────────────────────────────────────
    final_msg = f"{sr.title} 처리 완료 — {result_summary[:80]}"
    db.add(WorkLog(
        sr_id=sr_id, engineer=engineer,
        action_type=WorkActionType.RESULT,
        content="작업 결과 기록",
        result=final_msg, is_success=True,
    ))

    # ── SR → COMPLETED ────────────────────────────────────────────────────────
    sr.status = SRStatus.COMPLETED
    sr.updated_at = datetime.now()
    await _write_audit(db, sr_id, engineer, "SR_COMPLETED", final_msg)
    await db.commit()

    # ── 메신저 + 이메일 알림 (비동기, 실패 무시) ─────────────────────────────
    asyncio.create_task(_notify_messenger(sr, final_msg))
    from core.notify import notify_sr_status_changed as _notify
    asyncio.create_task(_notify(sr, SRStatus.COMPLETED, final_msg))

    return {"status": "COMPLETED", "sr_id": sr_id, "summary": final_msg}


@router.post("/{sr_id}/complete")
async def manual_complete(sr_id: str, engineer: str = "엔지니어",
                            result_note: str = "수동 완료 처리",
                            db: AsyncSession = Depends(get_db),
                            current_user: User = Depends(get_current_user)):
    """수동 완료 처리 + 메신저 알림."""
    r = await db.execute(select(SRRequest).where(SRRequest.sr_id == sr_id))
    sr = r.scalars().first()
    if not sr:
        raise HTTPException(404, "SR을 찾을 수 없습니다.")

    sr.status = SRStatus.COMPLETED
    sr.updated_at = datetime.now()
    db.add(WorkLog(
        sr_id=sr_id, engineer=engineer,
        action_type=WorkActionType.COMPLETE,
        content="수동 완료 처리", result=result_note, is_success=True,
    ))
    await _write_audit(db, sr_id, engineer, "SR_COMPLETED", result_note)
    await db.commit()

    asyncio.create_task(_notify_messenger(sr, result_note))
    from core.notify import notify_sr_status_changed as _notify
    asyncio.create_task(_notify(sr, SRStatus.COMPLETED, result_note))
    return {"status": "COMPLETED", "sr_id": sr_id}
