"""
그룹웨어 전자결재 연동 API

지원 플랫폼:
  - 카카오워크 (KAKAOWORK_BOT_TOKEN)
  - 네이버웍스 (NAVER_WORKS_BOT_ID / NAVER_WORKS_TOKEN)
  - 한컴오피스 (HANCOM_WEBHOOK_URL)
  - 사용자 정의 웹훅 (CUSTOM_APPROVAL_WEBHOOK_URL)

기능:
  1. SR 승인 요청 → 그룹웨어 결재 라인으로 발송
  2. 그룹웨어 승인/반려 콜백 → GUARDiA SR 상태 자동 갱신
  3. 결재 현황 조회

환경변수:
  GROUPWARE_TYPE = kakao|naver|hancom|custom
  KAKAOWORK_BOT_TOKEN = ...
  NAVER_WORKS_BOT_ID = ...
  NAVER_WORKS_TOKEN = ...
  HANCOM_WEBHOOK_URL = ...
  CUSTOM_APPROVAL_WEBHOOK_URL = ...
"""
from __future__ import annotations

import hashlib
import hmac
import json
import logging
import os
from datetime import datetime
from typing import Any, Optional

import httpx
from fastapi import APIRouter, BackgroundTasks, Depends, Header, HTTPException, Request
from pydantic import BaseModel
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 SRRequest, SRStatus, ApprovalFlow, User, UserRole

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

GROUPWARE_TYPE = os.getenv("GROUPWARE_TYPE", "")
KAKAO_TOKEN    = os.getenv("KAKAOWORK_BOT_TOKEN", "")
NAVER_BOT_ID   = os.getenv("NAVER_WORKS_BOT_ID", "")
NAVER_TOKEN    = os.getenv("NAVER_WORKS_TOKEN", "")
HANCOM_URL     = os.getenv("HANCOM_WEBHOOK_URL", "")
CUSTOM_URL     = os.getenv("CUSTOM_APPROVAL_WEBHOOK_URL", "")
WEBHOOK_SECRET = os.getenv("GROUPWARE_WEBHOOK_SECRET", "guardia-secret")

# 결재 요청 이력 (운영 시 DB 테이블로 이전)
_approval_requests: dict[str, dict] = {}


class ApprovalSendRequest(BaseModel):
    sr_id:      str
    approver:   str           # 결재자 사용자명 또는 이메일
    message:    Optional[str] = None
    platform:   Optional[str] = None   # None이면 환경변수 GROUPWARE_TYPE 사용


class CallbackRequest(BaseModel):
    action:    str    # approved | rejected
    sr_id:     str
    approver:  str
    comment:   Optional[str] = None
    signature: Optional[str] = None   # HMAC-SHA256 검증용


# ── 그룹웨어별 메시지 발송 ────────────────────────────────────────────────────

async def _send_kakao(sr_id: str, title: str, approver: str, message: str):
    """카카오워크 결재 메시지 발송."""
    if not KAKAO_TOKEN:
        logger.debug("KAKAOWORK_BOT_TOKEN 미설정")
        return False
    payload = {
        "conversationId": approver,
        "message": {
            "text": f"[GUARDiA 결재 요청]\n{message}",
            "blocks": [
                {"type": "header", "text": f"📋 결재 요청: {sr_id}", "style": "yellow"},
                {"type": "description", "term": "SR", "content": {"type": "text", "text": title}},
                {"type": "button", "text": "승인", "style": "primary",
                 "action": {"type": "call_modal", "value": f"approve:{sr_id}"}},
                {"type": "button", "text": "반려", "style": "default",
                 "action": {"type": "call_modal", "value": f"reject:{sr_id}"}},
            ]
        }
    }
    try:
        async with httpx.AsyncClient(timeout=10.0) as c:
            r = await c.post(
                "https://api.kakaowork.com/v1/messages.send",
                headers={"Authorization": f"Bearer {KAKAO_TOKEN}"},
                json=payload,
            )
            return r.status_code == 200
    except Exception as e:
        logger.warning("카카오워크 발송 실패: %s", e)
        return False


async def _send_naver_works(sr_id: str, title: str, approver: str, message: str):
    """네이버웍스 결재 메시지 발송."""
    if not NAVER_BOT_ID or not NAVER_TOKEN:
        return False
    payload = {
        "content": {
            "type":  "flex",
            "altText": f"[GUARDiA 결재 요청] {sr_id}",
            "contents": {
                "type": "bubble",
                "header": {"type": "box", "layout": "vertical",
                           "contents": [{"type": "text", "text": f"📋 결재 요청", "weight": "bold"}]},
                "body": {"type": "box", "layout": "vertical",
                         "contents": [{"type": "text", "text": f"SR: {sr_id}\n{message[:200]}"}]},
                "footer": {"type": "box", "layout": "horizontal", "contents": [
                    {"type": "button", "style": "primary", "action": {"type": "message", "label": "승인", "text": f"/approve {sr_id}"}},
                    {"type": "button", "style": "secondary", "action": {"type": "message", "label": "반려", "text": f"/reject {sr_id}"}},
                ]},
            }
        }
    }
    try:
        async with httpx.AsyncClient(timeout=10.0) as c:
            r = await c.post(
                f"https://www.worksapis.com/v1.0/bots/{NAVER_BOT_ID}/users/{approver}/messages",
                headers={"Authorization": f"Bearer {NAVER_TOKEN}", "Content-Type": "application/json"},
                json=payload,
            )
            return r.status_code in (200, 201)
    except Exception as e:
        logger.warning("네이버웍스 발송 실패: %s", e)
        return False


async def _send_hancom(sr_id: str, title: str, approver: str, message: str):
    """한컴오피스/그룹웨어 웹훅 발송."""
    if not HANCOM_URL:
        return False
    payload = {
        "event":    "approval_request",
        "sr_id":    sr_id,
        "title":    title,
        "approver": approver,
        "message":  message,
        "callback_url": f"{os.getenv('GUARDIA_BASE_URL','http://localhost:8001')}/api/groupware/callback",
    }
    try:
        async with httpx.AsyncClient(timeout=10.0) as c:
            r = await c.post(HANCOM_URL, json=payload)
            return r.status_code in (200, 201, 202)
    except Exception as e:
        logger.warning("한컴 발송 실패: %s", e)
        return False


async def _send_custom(sr_id: str, title: str, approver: str, message: str):
    """사용자 정의 그룹웨어 웹훅."""
    if not CUSTOM_URL:
        return False
    payload = {
        "type":     "approval_request",
        "sr_id":    sr_id,
        "title":    title,
        "approver": approver,
        "message":  message,
        "timestamp":datetime.utcnow().isoformat(),
        "callback_url": f"{os.getenv('GUARDIA_BASE_URL','http://localhost:8001')}/api/groupware/callback",
    }
    # HMAC 서명
    sig = hmac.new(WEBHOOK_SECRET.encode(), json.dumps(payload, sort_keys=True).encode(), hashlib.sha256).hexdigest()
    try:
        async with httpx.AsyncClient(timeout=10.0) as c:
            r = await c.post(CUSTOM_URL, json=payload, headers={"X-Signature": sig})
            return r.status_code in (200, 201, 202)
    except Exception as e:
        logger.warning("커스텀 웹훅 발송 실패: %s", e)
        return False


async def _dispatch(platform: str, sr_id: str, title: str, approver: str, message: str) -> bool:
    """플랫폼에 따라 결재 메시지 발송."""
    p = (platform or GROUPWARE_TYPE or "custom").lower()
    if p == "kakao":
        return await _send_kakao(sr_id, title, approver, message)
    elif p == "naver":
        return await _send_naver_works(sr_id, title, approver, message)
    elif p == "hancom":
        return await _send_hancom(sr_id, title, approver, message)
    else:
        return await _send_custom(sr_id, title, approver, message)


# ── 결재 요청 발송 API ────────────────────────────────────────────────────────

@router.post("/send-approval")
async def send_approval(
    body: ApprovalSendRequest,
    bg:   BackgroundTasks,
    db:   AsyncSession = Depends(get_db),
    cu:   User = Depends(get_current_user),
):
    """SR 승인 요청을 그룹웨어로 발송."""
    sr = (await db.execute(select(SRRequest).where(SRRequest.sr_id == body.sr_id))).scalars().first()
    if not sr:
        raise HTTPException(404, f"SR {body.sr_id}를 찾을 수 없습니다.")

    platform = body.platform or GROUPWARE_TYPE
    message  = body.message or (
        f"SR: {sr.sr_id}\n제목: {sr.title}\n요청자: {sr.requested_by}\n"
        f"우선순위: {sr.priority}\n\n처리 요청드립니다."
    )

    # 발송 이력 저장
    _approval_requests[sr.sr_id] = {
        "sr_id":     sr.sr_id,
        "approver":  body.approver,
        "platform":  platform,
        "sent_at":   datetime.utcnow().isoformat(),
        "status":    "PENDING",
    }

    # 백그라운드 발송
    async def _bg_send():
        ok = await _dispatch(platform, sr.sr_id, sr.title, body.approver, message)
        _approval_requests[sr.sr_id]["sent"] = ok
        logger.info("그룹웨어 결재 발송: sr=%s platform=%s ok=%s", sr.sr_id, platform, ok)

    bg.add_task(_bg_send)

    return {
        "message":  f"{platform or 'custom'} 그룹웨어로 결재 요청을 발송합니다.",
        "sr_id":    sr.sr_id,
        "approver": body.approver,
        "platform": platform or "custom",
    }


# ── 그룹웨어 콜백 수신 (승인/반려) ───────────────────────────────────────────

@router.post("/callback")
async def groupware_callback(
    body: CallbackRequest,
    db:   AsyncSession = Depends(get_db),
):
    """그룹웨어에서 승인/반려 콜백 수신 → SR 상태 자동 갱신."""
    if body.action not in ("approved", "rejected"):
        raise HTTPException(400, f"action은 approved|rejected 이어야 합니다.")

    sr = (await db.execute(select(SRRequest).where(SRRequest.sr_id == body.sr_id))).scalars().first()
    if not sr:
        raise HTTPException(404, f"SR {body.sr_id}를 찾을 수 없습니다.")

    # 승인/반려 처리
    from models import ApprovalResult, compute_log_hash, AuditLog
    result = ApprovalResult.APPROVED if body.action == "approved" else ApprovalResult.REJECTED

    apv = ApprovalFlow(
        sr_id      = body.sr_id,
        approver   = body.approver,
        result     = result,
        comment    = f"[그룹웨어 결재] {body.comment or ''}",
        decided_at = datetime.now(),
    )
    db.add(apv)

    old_status = sr.status
    if body.action == "approved":
        sr.status = SRStatus.APPROVED
    else:
        sr.status = SRStatus.REJECTED
    sr.updated_at = datetime.now()

    # 감사 로그
    from sqlalchemy import select as sel
    last_log = (await db.execute(
        sel(AuditLog).where(AuditLog.sr_id == body.sr_id).order_by(AuditLog.id.desc()).limit(1)
    )).scalars().first()
    prev_hash = last_log.log_hash if last_log else None
    ts = datetime.now().isoformat()
    db.add(AuditLog(
        sr_id     = body.sr_id,
        actor     = f"[그룹웨어]{body.approver}",
        action    = "SR_APPROVED" if body.action == "approved" else "SR_REJECTED",
        detail    = f"그룹웨어 결재: {body.action} | {body.comment or ''}",
        prev_hash = prev_hash,
        log_hash  = compute_log_hash(prev_hash, body.approver, body.action, "", ts),
    ))

    # 이력 갱신
    if body.sr_id in _approval_requests:
        _approval_requests[body.sr_id]["status"] = body.action.upper()
        _approval_requests[body.sr_id]["decided_at"] = datetime.utcnow().isoformat()

    await db.commit()

    return {
        "message":    f"SR {body.sr_id} — {body.action} 처리 완료",
        "old_status": old_status,
        "new_status": sr.status,
    }


# ── 결재 현황 조회 ────────────────────────────────────────────────────────────

@router.get("/approvals")
async def list_approvals(_u: User = Depends(get_current_user)):
    """그룹웨어 결재 발송 이력 조회."""
    return {
        "enabled":  bool(GROUPWARE_TYPE or KAKAO_TOKEN or NAVER_BOT_ID or HANCOM_URL or CUSTOM_URL),
        "platform": GROUPWARE_TYPE or "미설정",
        "approvals": list(_approval_requests.values()),
    }


@router.get("/config")
async def groupware_config(_u: User = Depends(get_current_user)):
    """그룹웨어 연동 설정 현황 (민감 정보 제외)."""
    return {
        "configured_platforms": [
            p for p, flag in [
                ("kakao",   bool(KAKAO_TOKEN)),
                ("naver",   bool(NAVER_BOT_ID and NAVER_TOKEN)),
                ("hancom",  bool(HANCOM_URL)),
                ("custom",  bool(CUSTOM_URL)),
            ] if flag
        ],
        "default_platform": GROUPWARE_TYPE or "none",
        "callback_url":     f"{os.getenv('GUARDIA_BASE_URL','http://localhost:8001')}/api/groupware/callback",
    }
